var JSPlayerModule = (() => {
  var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src :
    undefined;

  return (
    function(moduleArg = {}) {

      function GROWABLE_HEAP_I8() {
        if (wasmMemory.buffer != HEAP8.buffer) {
          updateMemoryViews()
        }
        return HEAP8
      }

      function GROWABLE_HEAP_U8() {
        if (wasmMemory.buffer != HEAP8.buffer) {
          updateMemoryViews()
        }
        return HEAPU8
      }

      function GROWABLE_HEAP_I16() {
        if (wasmMemory.buffer != HEAP8.buffer) {
          updateMemoryViews()
        }
        return HEAP16
      }

      function GROWABLE_HEAP_U16() {
        if (wasmMemory.buffer != HEAP8.buffer) {
          updateMemoryViews()
        }
        return HEAPU16
      }

      function GROWABLE_HEAP_I32() {
        if (wasmMemory.buffer != HEAP8.buffer) {
          updateMemoryViews()
        }
        return HEAP32
      }

      function GROWABLE_HEAP_U32() {
        if (wasmMemory.buffer != HEAP8.buffer) {
          updateMemoryViews()
        }
        return HEAPU32
      }

      function GROWABLE_HEAP_F32() {
        if (wasmMemory.buffer != HEAP8.buffer) {
          updateMemoryViews()
        }
        return HEAPF32
      }

      function GROWABLE_HEAP_F64() {
        if (wasmMemory.buffer != HEAP8.buffer) {
          updateMemoryViews()
        }
        return HEAPF64
      }
      var Module = moduleArg;
      var readyPromiseResolve, readyPromiseReject;
      Module["ready"] = new Promise((resolve, reject) => {
        readyPromiseResolve = resolve;
        readyPromiseReject = reject
      });
      var moduleOverrides = Object.assign({}, Module);
      var arguments_ = [];
      var thisProgram = "./this.program";
      var quit_ = (status, toThrow) => {
        throw toThrow
      };
      var ENVIRONMENT_IS_WEB = typeof window == "object";
      var ENVIRONMENT_IS_WORKER = typeof importScripts == "function";
      var ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" &&
        typeof process.versions.node == "string";
      var ENVIRONMENT_IS_PTHREAD = Module["ENVIRONMENT_IS_PTHREAD"] || false;
      var scriptDirectory = "";

      function locateFile(path) {
        if (Module["locateFile"]) {
          return Module["locateFile"](path, scriptDirectory)
        }
        return scriptDirectory + path
      }
      var read_, readAsync, readBinary, setWindowTitle;
      if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
        if (ENVIRONMENT_IS_WORKER) {
          scriptDirectory = self.location.href
        } else if (typeof document != "undefined" && document.currentScript) {
          scriptDirectory = document.currentScript.src
        }
        if (_scriptDir) {
          scriptDirectory = _scriptDir
        }
        if (scriptDirectory.indexOf("blob:") !== 0) {
          scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1)
        } else {
          scriptDirectory = ""
        } {
          read_ = url => {
            var xhr = new XMLHttpRequest;
            xhr.open("GET", url, false);
            xhr.send(null);
            return xhr.responseText
          };
          if (ENVIRONMENT_IS_WORKER) {
            readBinary = url => {
              var xhr = new XMLHttpRequest;
              xhr.open("GET", url, false);
              xhr.responseType = "arraybuffer";
              xhr.send(null);
              return new Uint8Array(xhr.response)
            }
          }
          readAsync = (url, onload, onerror) => {
            var xhr = new XMLHttpRequest;
            xhr.open("GET", url, true);
            xhr.responseType = "arraybuffer";
            xhr.onload = () => {
              if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
                onload(xhr.response);
                return
              }
              onerror()
            };
            xhr.onerror = onerror;
            xhr.send(null)
          }
        }
        setWindowTitle = title => document.title = title
      } else {}
      var out = Module["print"] || console.log.bind(console);
      var err = Module["printErr"] || console.error.bind(console);
      Object.assign(Module, moduleOverrides);
      moduleOverrides = null;
      if (Module["arguments"]) arguments_ = Module["arguments"];
      if (Module["thisProgram"]) thisProgram = Module["thisProgram"];
      if (Module["quit"]) quit_ = Module["quit"];
      var wasmBinary;
      if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"];
      var noExitRuntime = Module["noExitRuntime"] || true;
      if (typeof WebAssembly != "object") {
        abort("no native wasm support detected")
      }
      var wasmMemory;
      var wasmModule;
      var ABORT = false;
      var EXITSTATUS;

      function assert(condition, text) {
        if (!condition) {
          abort(text)
        }
      }
      var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;

      function updateMemoryViews() {
        var b = wasmMemory.buffer;
        Module["HEAP8"] = HEAP8 = new Int8Array(b);
        Module["HEAP16"] = HEAP16 = new Int16Array(b);
        Module["HEAP32"] = HEAP32 = new Int32Array(b);
        Module["HEAPU8"] = HEAPU8 = new Uint8Array(b);
        Module["HEAPU16"] = HEAPU16 = new Uint16Array(b);
        Module["HEAPU32"] = HEAPU32 = new Uint32Array(b);
        Module["HEAPF32"] = HEAPF32 = new Float32Array(b);
        Module["HEAPF64"] = HEAPF64 = new Float64Array(b)
      }
      var INITIAL_MEMORY = Module["INITIAL_MEMORY"] || 524288e3;
      assert(INITIAL_MEMORY >= 1048576, "INITIAL_MEMORY should be larger than STACK_SIZE, was " + INITIAL_MEMORY +
        "! (STACK_SIZE=" + 1048576 + ")");
      if (ENVIRONMENT_IS_PTHREAD) {
        wasmMemory = Module["wasmMemory"]
      } else {
        if (Module["wasmMemory"]) {
          wasmMemory = Module["wasmMemory"]
        } else {
          wasmMemory = new WebAssembly.Memory({
            "initial": INITIAL_MEMORY / 65536,
            "maximum": 1072693248 / 65536,
            "shared": true
          });
          if (!(wasmMemory.buffer instanceof SharedArrayBuffer)) {
            err(
              "requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag");
            if (ENVIRONMENT_IS_NODE) {
              err(
                "(on node you may need: --experimental-wasm-threads --experimental-wasm-bulk-memory and/or recent version)")
            }
            throw Error("bad memory")
          }
        }
      }
      updateMemoryViews();
      INITIAL_MEMORY = wasmMemory.buffer.byteLength;
      var wasmTable;
      var __ATPRERUN__ = [];
      var __ATINIT__ = [];
      var __ATEXIT__ = [];
      var __ATPOSTRUN__ = [];
      var runtimeInitialized = false;
      var runtimeKeepaliveCounter = 0;

      function keepRuntimeAlive() {
        return noExitRuntime || runtimeKeepaliveCounter > 0
      }

      function preRun() {
        if (Module["preRun"]) {
          if (typeof Module["preRun"] == "function") Module["preRun"] = [Module["preRun"]];
          while (Module["preRun"].length) {
            addOnPreRun(Module["preRun"].shift())
          }
        }
        callRuntimeCallbacks(__ATPRERUN__)
      }

      function initRuntime() {
        runtimeInitialized = true;
        if (ENVIRONMENT_IS_PTHREAD) return;
        if (!Module["noFSInit"] && !FS.init.initialized) FS.init();
        FS.ignorePermissions = false;
        TTY.init();
        callRuntimeCallbacks(__ATINIT__)
      }

      function postRun() {
        if (ENVIRONMENT_IS_PTHREAD) return;
        if (Module["postRun"]) {
          if (typeof Module["postRun"] == "function") Module["postRun"] = [Module["postRun"]];
          while (Module["postRun"].length) {
            addOnPostRun(Module["postRun"].shift())
          }
        }
        callRuntimeCallbacks(__ATPOSTRUN__)
      }

      function addOnPreRun(cb) {
        __ATPRERUN__.unshift(cb)
      }

      function addOnInit(cb) {
        __ATINIT__.unshift(cb)
      }

      function addOnPostRun(cb) {
        __ATPOSTRUN__.unshift(cb)
      }
      var runDependencies = 0;
      var runDependencyWatcher = null;
      var dependenciesFulfilled = null;

      function getUniqueRunDependency(id) {
        return id
      }

      function addRunDependency(id) {
        runDependencies++;
        if (Module["monitorRunDependencies"]) {
          Module["monitorRunDependencies"](runDependencies)
        }
      }

      function removeRunDependency(id) {
        runDependencies--;
        if (Module["monitorRunDependencies"]) {
          Module["monitorRunDependencies"](runDependencies)
        }
        if (runDependencies == 0) {
          if (runDependencyWatcher !== null) {
            clearInterval(runDependencyWatcher);
            runDependencyWatcher = null
          }
          if (dependenciesFulfilled) {
            var callback = dependenciesFulfilled;
            dependenciesFulfilled = null;
            callback()
          }
        }
      }

      function abort(what) {
        if (Module["onAbort"]) {
          Module["onAbort"](what)
        }
        what = "Aborted(" + what + ")";
        err(what);
        ABORT = true;
        EXITSTATUS = 1;
        what += ". Build with -sASSERTIONS for more info.";
        var e = new WebAssembly.RuntimeError(what);
        readyPromiseReject(e);
        throw e
      }
      var dataURIPrefix = "data:application/octet-stream;base64,";

      function isDataURI(filename) {
        return filename.startsWith(dataURIPrefix)
      }
      var wasmBinaryFile;
      wasmBinaryFile = "Decoder.wasm";
      if (!isDataURI(wasmBinaryFile)) {
        wasmBinaryFile = locateFile(wasmBinaryFile)
      }

      function getBinary(file) {
        try {
          if (file == wasmBinaryFile && wasmBinary) {
            return new Uint8Array(wasmBinary)
          }
          if (readBinary) {
            return readBinary(file)
          }
          throw "both async and sync fetching of the wasm failed"
        } catch (err) {
          abort(err)
        }
      }

      function getBinaryPromise(binaryFile) {
        if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {
          if (typeof fetch == "function") {
            return fetch(binaryFile, {
              credentials: "same-origin"
            }).then(response => {
              if (!response["ok"]) {
                throw "failed to load wasm binary file at '" + binaryFile + "'"
              }
              return response["arrayBuffer"]()
            }).catch(() => getBinary(binaryFile))
          }
        }
        return Promise.resolve().then(() => getBinary(binaryFile))
      }

      function instantiateArrayBuffer(binaryFile, imports, receiver) {
        return getBinaryPromise(binaryFile).then(binary => {
          return WebAssembly.instantiate(binary, imports)
        }).then(instance => {
          return instance
        }).then(receiver, reason => {
          err("failed to asynchronously prepare wasm: " + reason);
          abort(reason)
        })
      }

      function instantiateAsync(binary, binaryFile, imports, callback) {
        if (!binary && typeof WebAssembly.instantiateStreaming == "function" && !isDataURI(binaryFile) &&
          typeof fetch == "function") {
          return fetch(binaryFile, {
            credentials: "same-origin"
          }).then(response => {
            var result = WebAssembly.instantiateStreaming(response, imports);
            return result.then(callback, function(reason) {
              err("wasm streaming compile failed: " + reason);
              err("falling back to ArrayBuffer instantiation");
              return instantiateArrayBuffer(binaryFile, imports, callback)
            })
          })
        } else {
          return instantiateArrayBuffer(binaryFile, imports, callback)
        }
      }

      function createWasm() {
        var info = {
          "env": wasmImports,
          "wasi_snapshot_preview1": wasmImports
        };

        function receiveInstance(instance, module) {
          var exports = instance.exports;
          Module["asm"] = exports;
          registerTLSInit(Module["asm"]["_emscripten_tls_init"]);
          wasmTable = Module["asm"]["__indirect_function_table"];
          addOnInit(Module["asm"]["__wasm_call_ctors"]);
          wasmModule = module;
          removeRunDependency("wasm-instantiate");
          return exports
        }
        addRunDependency("wasm-instantiate");

        function receiveInstantiationResult(result) {
          receiveInstance(result["instance"], result["module"])
        }
        if (Module["instantiateWasm"]) {
          try {
            return Module["instantiateWasm"](info, receiveInstance)
          } catch (e) {
            err("Module.instantiateWasm callback failed with error: " + e);
            readyPromiseReject(e)
          }
        }
        instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult).catch(readyPromiseReject);
        return {}
      }
      var tempDouble;
      var tempI64;
      var ASM_CONSTS = {
        699204: $0 => {
          Module["firstGLContextExt"] = GL.contexts[$0].GLctx.getExtension("WEBGL_lose_context")
        },
        699296: () => {
          Module["firstGLContextExt"].loseContext()
        },
        699343: () => {
          return GROWABLE_HEAP_I8().length
        },
        699363: () => {
          return GROWABLE_HEAP_I8().length
        }
      };

      function ExitStatus(status) {
        this.name = "ExitStatus";
        this.message = `Program terminated with exit(${status})`;
        this.status = status
      }
      var terminateWorker = function(worker) {
        worker.terminate();
        worker.onmessage = e => {}
      };

      function killThread(pthread_ptr) {
        var worker = PThread.pthreads[pthread_ptr];
        delete PThread.pthreads[pthread_ptr];
        terminateWorker(worker);
        __emscripten_thread_free_data(pthread_ptr);
        PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(worker), 1);
        worker.pthread_ptr = 0
      }

      function cancelThread(pthread_ptr) {
        var worker = PThread.pthreads[pthread_ptr];
        worker.postMessage({
          "cmd": "cancel"
        })
      }

      function cleanupThread(pthread_ptr) {
        var worker = PThread.pthreads[pthread_ptr];
        assert(worker);
        PThread.returnWorkerToPool(worker)
      }

      function spawnThread(threadParams) {
        var worker = PThread.getNewWorker();
        if (!worker) {
          return 6
        }
        PThread.runningWorkers.push(worker);
        PThread.pthreads[threadParams.pthread_ptr] = worker;
        worker.pthread_ptr = threadParams.pthread_ptr;
        var msg = {
          "cmd": "run",
          "start_routine": threadParams.startRoutine,
          "arg": threadParams.arg,
          "pthread_ptr": threadParams.pthread_ptr
        };
        msg.moduleCanvasId = threadParams.moduleCanvasId;
        msg.offscreenCanvases = threadParams.offscreenCanvases;
        worker.postMessage(msg, threadParams.transferList);
        return 0
      }
      var PATH = {
        isAbs: path => path.charAt(0) === "/",
        splitPath: filename => {
          var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
          return splitPathRe.exec(filename).slice(1)
        },
        normalizeArray: (parts, allowAboveRoot) => {
          var up = 0;
          for (var i = parts.length - 1; i >= 0; i--) {
            var last = parts[i];
            if (last === ".") {
              parts.splice(i, 1)
            } else if (last === "..") {
              parts.splice(i, 1);
              up++
            } else if (up) {
              parts.splice(i, 1);
              up--
            }
          }
          if (allowAboveRoot) {
            for (; up; up--) {
              parts.unshift("..")
            }
          }
          return parts
        },
        normalize: path => {
          var isAbsolute = PATH.isAbs(path),
            trailingSlash = path.substr(-1) === "/";
          path = PATH.normalizeArray(path.split("/").filter(p => !!p), !isAbsolute).join("/");
          if (!path && !isAbsolute) {
            path = "."
          }
          if (path && trailingSlash) {
            path += "/"
          }
          return (isAbsolute ? "/" : "") + path
        },
        dirname: path => {
          var result = PATH.splitPath(path),
            root = result[0],
            dir = result[1];
          if (!root && !dir) {
            return "."
          }
          if (dir) {
            dir = dir.substr(0, dir.length - 1)
          }
          return root + dir
        },
        basename: path => {
          if (path === "/") return "/";
          path = PATH.normalize(path);
          path = path.replace(/\/$/, "");
          var lastSlash = path.lastIndexOf("/");
          if (lastSlash === -1) return path;
          return path.substr(lastSlash + 1)
        },
        join: function() {
          var paths = Array.prototype.slice.call(arguments);
          return PATH.normalize(paths.join("/"))
        },
        join2: (l, r) => {
          return PATH.normalize(l + "/" + r)
        }
      };
      var initRandomFill = () => {
        if (typeof crypto == "object" && typeof crypto["getRandomValues"] == "function") {
          return view => (view.set(crypto.getRandomValues(new Uint8Array(view.byteLength))), view)
        } else abort("initRandomDevice")
      };
      var randomFill = view => {
        return (randomFill = initRandomFill())(view)
      };
      var PATH_FS = {
        resolve: function() {
          var resolvedPath = "",
            resolvedAbsolute = false;
          for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
            var path = i >= 0 ? arguments[i] : FS.cwd();
            if (typeof path != "string") {
              throw new TypeError("Arguments to path.resolve must be strings")
            } else if (!path) {
              return ""
            }
            resolvedPath = path + "/" + resolvedPath;
            resolvedAbsolute = PATH.isAbs(path)
          }
          resolvedPath = PATH.normalizeArray(resolvedPath.split("/").filter(p => !!p), !resolvedAbsolute)
            .join("/");
          return (resolvedAbsolute ? "/" : "") + resolvedPath || "."
        },
        relative: (from, to) => {
          from = PATH_FS.resolve(from).substr(1);
          to = PATH_FS.resolve(to).substr(1);

          function trim(arr) {
            var start = 0;
            for (; start < arr.length; start++) {
              if (arr[start] !== "") break
            }
            var end = arr.length - 1;
            for (; end >= 0; end--) {
              if (arr[end] !== "") break
            }
            if (start > end) return [];
            return arr.slice(start, end - start + 1)
          }
          var fromParts = trim(from.split("/"));
          var toParts = trim(to.split("/"));
          var length = Math.min(fromParts.length, toParts.length);
          var samePartsLength = length;
          for (var i = 0; i < length; i++) {
            if (fromParts[i] !== toParts[i]) {
              samePartsLength = i;
              break
            }
          }
          var outputParts = [];
          for (var i = samePartsLength; i < fromParts.length; i++) {
            outputParts.push("..")
          }
          outputParts = outputParts.concat(toParts.slice(samePartsLength));
          return outputParts.join("/")
        }
      };
      var lengthBytesUTF8 = str => {
        var len = 0;
        for (var i = 0; i < str.length; ++i) {
          var c = str.charCodeAt(i);
          if (c <= 127) {
            len++
          } else if (c <= 2047) {
            len += 2
          } else if (c >= 55296 && c <= 57343) {
            len += 4;
            ++i
          } else {
            len += 3
          }
        }
        return len
      };
      var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => {
        if (!(maxBytesToWrite > 0)) return 0;
        var startIdx = outIdx;
        var endIdx = outIdx + maxBytesToWrite - 1;
        for (var i = 0; i < str.length; ++i) {
          var u = str.charCodeAt(i);
          if (u >= 55296 && u <= 57343) {
            var u1 = str.charCodeAt(++i);
            u = 65536 + ((u & 1023) << 10) | u1 & 1023
          }
          if (u <= 127) {
            if (outIdx >= endIdx) break;
            heap[outIdx++] = u
          } else if (u <= 2047) {
            if (outIdx + 1 >= endIdx) break;
            heap[outIdx++] = 192 | u >> 6;
            heap[outIdx++] = 128 | u & 63
          } else if (u <= 65535) {
            if (outIdx + 2 >= endIdx) break;
            heap[outIdx++] = 224 | u >> 12;
            heap[outIdx++] = 128 | u >> 6 & 63;
            heap[outIdx++] = 128 | u & 63
          } else {
            if (outIdx + 3 >= endIdx) break;
            heap[outIdx++] = 240 | u >> 18;
            heap[outIdx++] = 128 | u >> 12 & 63;
            heap[outIdx++] = 128 | u >> 6 & 63;
            heap[outIdx++] = 128 | u & 63
          }
        }
        heap[outIdx] = 0;
        return outIdx - startIdx
      };

      function intArrayFromString(stringy, dontAddNull, length) {
        var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1;
        var u8array = new Array(len);
        var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length);
        if (dontAddNull) u8array.length = numBytesWritten;
        return u8array
      }
      var UTF8Decoder = typeof TextDecoder != "undefined" ? new TextDecoder("utf8") : undefined;
      var UTF8ArrayToString = (heapOrArray, idx, maxBytesToRead) => {
        var endIdx = idx + maxBytesToRead;
        var endPtr = idx;
        while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr;
        if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
          return UTF8Decoder.decode(heapOrArray.buffer instanceof SharedArrayBuffer ? heapOrArray.slice(idx,
            endPtr) : heapOrArray.subarray(idx, endPtr))
        }
        var str = "";
        while (idx < endPtr) {
          var u0 = heapOrArray[idx++];
          if (!(u0 & 128)) {
            str += String.fromCharCode(u0);
            continue
          }
          var u1 = heapOrArray[idx++] & 63;
          if ((u0 & 224) == 192) {
            str += String.fromCharCode((u0 & 31) << 6 | u1);
            continue
          }
          var u2 = heapOrArray[idx++] & 63;
          if ((u0 & 240) == 224) {
            u0 = (u0 & 15) << 12 | u1 << 6 | u2
          } else {
            u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | heapOrArray[idx++] & 63
          }
          if (u0 < 65536) {
            str += String.fromCharCode(u0)
          } else {
            var ch = u0 - 65536;
            str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023)
          }
        }
        return str
      };
      var TTY = {
        ttys: [],
        init: function() {},
        shutdown: function() {},
        register: function(dev, ops) {
          TTY.ttys[dev] = {
            input: [],
            output: [],
            ops: ops
          };
          FS.registerDevice(dev, TTY.stream_ops)
        },
        stream_ops: {
          open: function(stream) {
            var tty = TTY.ttys[stream.node.rdev];
            if (!tty) {
              throw new FS.ErrnoError(43)
            }
            stream.tty = tty;
            stream.seekable = false
          },
          close: function(stream) {
            stream.tty.ops.fsync(stream.tty)
          },
          fsync: function(stream) {
            stream.tty.ops.fsync(stream.tty)
          },
          read: function(stream, buffer, offset, length, pos) {
            if (!stream.tty || !stream.tty.ops.get_char) {
              throw new FS.ErrnoError(60)
            }
            var bytesRead = 0;
            for (var i = 0; i < length; i++) {
              var result;
              try {
                result = stream.tty.ops.get_char(stream.tty)
              } catch (e) {
                throw new FS.ErrnoError(29)
              }
              if (result === undefined && bytesRead === 0) {
                throw new FS.ErrnoError(6)
              }
              if (result === null || result === undefined) break;
              bytesRead++;
              buffer[offset + i] = result
            }
            if (bytesRead) {
              stream.node.timestamp = Date.now()
            }
            return bytesRead
          },
          write: function(stream, buffer, offset, length, pos) {
            if (!stream.tty || !stream.tty.ops.put_char) {
              throw new FS.ErrnoError(60)
            }
            try {
              for (var i = 0; i < length; i++) {
                stream.tty.ops.put_char(stream.tty, buffer[offset + i])
              }
            } catch (e) {
              throw new FS.ErrnoError(29)
            }
            if (length) {
              stream.node.timestamp = Date.now()
            }
            return i
          }
        },
        default_tty_ops: {
          get_char: function(tty) {
            if (!tty.input.length) {
              var result = null;
              if (typeof window != "undefined" && typeof window.prompt == "function") {
                result = window.prompt("Input: ");
                if (result !== null) {
                  result += "\n"
                }
              } else if (typeof readline == "function") {
                result = readline();
                if (result !== null) {
                  result += "\n"
                }
              }
              if (!result) {
                return null
              }
              tty.input = intArrayFromString(result, true)
            }
            return tty.input.shift()
          },
          put_char: function(tty, val) {
            if (val === null || val === 10) {
              out(UTF8ArrayToString(tty.output, 0));
              tty.output = []
            } else {
              if (val != 0) tty.output.push(val)
            }
          },
          fsync: function(tty) {
            if (tty.output && tty.output.length > 0) {
              out(UTF8ArrayToString(tty.output, 0));
              tty.output = []
            }
          },
          ioctl_tcgets: function(tty) {
            return {
              c_iflag: 25856,
              c_oflag: 5,
              c_cflag: 191,
              c_lflag: 35387,
              c_cc: [3, 28, 127, 21, 4, 0, 1, 0, 17, 19, 26, 0, 18, 15, 23, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0
              ]
            }
          },
          ioctl_tcsets: function(tty, optional_actions, data) {
            return 0
          },
          ioctl_tiocgwinsz: function(tty) {
            return [24, 80]
          }
        },
        default_tty1_ops: {
          put_char: function(tty, val) {
            if (val === null || val === 10) {
              err(UTF8ArrayToString(tty.output, 0));
              tty.output = []
            } else {
              if (val != 0) tty.output.push(val)
            }
          },
          fsync: function(tty) {
            if (tty.output && tty.output.length > 0) {
              err(UTF8ArrayToString(tty.output, 0));
              tty.output = []
            }
          }
        }
      };
      var mmapAlloc = size => {
        abort()
      };
      var MEMFS = {
        ops_table: null,
        mount: function(mount) {
          return MEMFS.createNode(null, "/", 16384 | 511, 0)
        },
        createNode: function(parent, name, mode, dev) {
          if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
            throw new FS.ErrnoError(63)
          }
          if (!MEMFS.ops_table) {
            MEMFS.ops_table = {
              dir: {
                node: {
                  getattr: MEMFS.node_ops.getattr,
                  setattr: MEMFS.node_ops.setattr,
                  lookup: MEMFS.node_ops.lookup,
                  mknod: MEMFS.node_ops.mknod,
                  rename: MEMFS.node_ops.rename,
                  unlink: MEMFS.node_ops.unlink,
                  rmdir: MEMFS.node_ops.rmdir,
                  readdir: MEMFS.node_ops.readdir,
                  symlink: MEMFS.node_ops.symlink
                },
                stream: {
                  llseek: MEMFS.stream_ops.llseek
                }
              },
              file: {
                node: {
                  getattr: MEMFS.node_ops.getattr,
                  setattr: MEMFS.node_ops.setattr
                },
                stream: {
                  llseek: MEMFS.stream_ops.llseek,
                  read: MEMFS.stream_ops.read,
                  write: MEMFS.stream_ops.write,
                  allocate: MEMFS.stream_ops.allocate,
                  mmap: MEMFS.stream_ops.mmap,
                  msync: MEMFS.stream_ops.msync
                }
              },
              link: {
                node: {
                  getattr: MEMFS.node_ops.getattr,
                  setattr: MEMFS.node_ops.setattr,
                  readlink: MEMFS.node_ops.readlink
                },
                stream: {}
              },
              chrdev: {
                node: {
                  getattr: MEMFS.node_ops.getattr,
                  setattr: MEMFS.node_ops.setattr
                },
                stream: FS.chrdev_stream_ops
              }
            }
          }
          var node = FS.createNode(parent, name, mode, dev);
          if (FS.isDir(node.mode)) {
            node.node_ops = MEMFS.ops_table.dir.node;
            node.stream_ops = MEMFS.ops_table.dir.stream;
            node.contents = {}
          } else if (FS.isFile(node.mode)) {
            node.node_ops = MEMFS.ops_table.file.node;
            node.stream_ops = MEMFS.ops_table.file.stream;
            node.usedBytes = 0;
            node.contents = null
          } else if (FS.isLink(node.mode)) {
            node.node_ops = MEMFS.ops_table.link.node;
            node.stream_ops = MEMFS.ops_table.link.stream
          } else if (FS.isChrdev(node.mode)) {
            node.node_ops = MEMFS.ops_table.chrdev.node;
            node.stream_ops = MEMFS.ops_table.chrdev.stream
          }
          node.timestamp = Date.now();
          if (parent) {
            parent.contents[name] = node;
            parent.timestamp = node.timestamp
          }
          return node
        },
        getFileDataAsTypedArray: function(node) {
          if (!node.contents) return new Uint8Array(0);
          if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes);
          return new Uint8Array(node.contents)
        },
        expandFileStorage: function(node, newCapacity) {
          var prevCapacity = node.contents ? node.contents.length : 0;
          if (prevCapacity >= newCapacity) return;
          var CAPACITY_DOUBLING_MAX = 1024 * 1024;
          newCapacity = Math.max(newCapacity, prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 :
            1.125) >>> 0);
          if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256);
          var oldContents = node.contents;
          node.contents = new Uint8Array(newCapacity);
          if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0)
        },
        resizeFileStorage: function(node, newSize) {
          if (node.usedBytes == newSize) return;
          if (newSize == 0) {
            node.contents = null;
            node.usedBytes = 0
          } else {
            var oldContents = node.contents;
            node.contents = new Uint8Array(newSize);
            if (oldContents) {
              node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes)))
            }
            node.usedBytes = newSize
          }
        },
        node_ops: {
          getattr: function(node) {
            var attr = {};
            attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
            attr.ino = node.id;
            attr.mode = node.mode;
            attr.nlink = 1;
            attr.uid = 0;
            attr.gid = 0;
            attr.rdev = node.rdev;
            if (FS.isDir(node.mode)) {
              attr.size = 4096
            } else if (FS.isFile(node.mode)) {
              attr.size = node.usedBytes
            } else if (FS.isLink(node.mode)) {
              attr.size = node.link.length
            } else {
              attr.size = 0
            }
            attr.atime = new Date(node.timestamp);
            attr.mtime = new Date(node.timestamp);
            attr.ctime = new Date(node.timestamp);
            attr.blksize = 4096;
            attr.blocks = Math.ceil(attr.size / attr.blksize);
            return attr
          },
          setattr: function(node, attr) {
            if (attr.mode !== undefined) {
              node.mode = attr.mode
            }
            if (attr.timestamp !== undefined) {
              node.timestamp = attr.timestamp
            }
            if (attr.size !== undefined) {
              MEMFS.resizeFileStorage(node, attr.size)
            }
          },
          lookup: function(parent, name) {
            throw FS.genericErrors[44]
          },
          mknod: function(parent, name, mode, dev) {
            return MEMFS.createNode(parent, name, mode, dev)
          },
          rename: function(old_node, new_dir, new_name) {
            if (FS.isDir(old_node.mode)) {
              var new_node;
              try {
                new_node = FS.lookupNode(new_dir, new_name)
              } catch (e) {}
              if (new_node) {
                for (var i in new_node.contents) {
                  throw new FS.ErrnoError(55)
                }
              }
            }
            delete old_node.parent.contents[old_node.name];
            old_node.parent.timestamp = Date.now();
            old_node.name = new_name;
            new_dir.contents[new_name] = old_node;
            new_dir.timestamp = old_node.parent.timestamp;
            old_node.parent = new_dir
          },
          unlink: function(parent, name) {
            delete parent.contents[name];
            parent.timestamp = Date.now()
          },
          rmdir: function(parent, name) {
            var node = FS.lookupNode(parent, name);
            for (var i in node.contents) {
              throw new FS.ErrnoError(55)
            }
            delete parent.contents[name];
            parent.timestamp = Date.now()
          },
          readdir: function(node) {
            var entries = [".", ".."];
            for (var key in node.contents) {
              if (!node.contents.hasOwnProperty(key)) {
                continue
              }
              entries.push(key)
            }
            return entries
          },
          symlink: function(parent, newname, oldpath) {
            var node = MEMFS.createNode(parent, newname, 511 | 40960, 0);
            node.link = oldpath;
            return node
          },
          readlink: function(node) {
            if (!FS.isLink(node.mode)) {
              throw new FS.ErrnoError(28)
            }
            return node.link
          }
        },
        stream_ops: {
          read: function(stream, buffer, offset, length, position) {
            var contents = stream.node.contents;
            if (position >= stream.node.usedBytes) return 0;
            var size = Math.min(stream.node.usedBytes - position, length);
            if (size > 8 && contents.subarray) {
              buffer.set(contents.subarray(position, position + size), offset)
            } else {
              for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i]
            }
            return size
          },
          write: function(stream, buffer, offset, length, position, canOwn) {
            if (buffer.buffer === GROWABLE_HEAP_I8().buffer) {
              canOwn = false
            }
            if (!length) return 0;
            var node = stream.node;
            node.timestamp = Date.now();
            if (buffer.subarray && (!node.contents || node.contents.subarray)) {
              if (canOwn) {
                node.contents = buffer.subarray(offset, offset + length);
                node.usedBytes = length;
                return length
              } else if (node.usedBytes === 0 && position === 0) {
                node.contents = buffer.slice(offset, offset + length);
                node.usedBytes = length;
                return length
              } else if (position + length <= node.usedBytes) {
                node.contents.set(buffer.subarray(offset, offset + length), position);
                return length
              }
            }
            MEMFS.expandFileStorage(node, position + length);
            if (node.contents.subarray && buffer.subarray) {
              node.contents.set(buffer.subarray(offset, offset + length), position)
            } else {
              for (var i = 0; i < length; i++) {
                node.contents[position + i] = buffer[offset + i]
              }
            }
            node.usedBytes = Math.max(node.usedBytes, position + length);
            return length
          },
          llseek: function(stream, offset, whence) {
            var position = offset;
            if (whence === 1) {
              position += stream.position
            } else if (whence === 2) {
              if (FS.isFile(stream.node.mode)) {
                position += stream.node.usedBytes
              }
            }
            if (position < 0) {
              throw new FS.ErrnoError(28)
            }
            return position
          },
          allocate: function(stream, offset, length) {
            MEMFS.expandFileStorage(stream.node, offset + length);
            stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length)
          },
          mmap: function(stream, length, position, prot, flags) {
            if (!FS.isFile(stream.node.mode)) {
              throw new FS.ErrnoError(43)
            }
            var ptr;
            var allocated;
            var contents = stream.node.contents;
            if (!(flags & 2) && contents.buffer === GROWABLE_HEAP_I8().buffer) {
              allocated = false;
              ptr = contents.byteOffset
            } else {
              if (position > 0 || position + length < contents.length) {
                if (contents.subarray) {
                  contents = contents.subarray(position, position + length)
                } else {
                  contents = Array.prototype.slice.call(contents, position, position + length)
                }
              }
              allocated = true;
              ptr = mmapAlloc(length);
              if (!ptr) {
                throw new FS.ErrnoError(48)
              }
              GROWABLE_HEAP_I8().set(contents, ptr)
            }
            return {
              ptr: ptr,
              allocated: allocated
            }
          },
          msync: function(stream, buffer, offset, length, mmapFlags) {
            MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false);
            return 0
          }
        }
      };
      var asyncLoad = (url, onload, onerror, noRunDep) => {
        var dep = !noRunDep ? getUniqueRunDependency(`al ${url}`) : "";
        readAsync(url, arrayBuffer => {
          assert(arrayBuffer, `Loading data file "${url}" failed (no arrayBuffer).`);
          onload(new Uint8Array(arrayBuffer));
          if (dep) removeRunDependency(dep)
        }, event => {
          if (onerror) {
            onerror()
          } else {
            throw `Loading data file "${url}" failed.`
          }
        });
        if (dep) addRunDependency(dep)
      };
      var preloadPlugins = Module["preloadPlugins"] || [];

      function FS_handledByPreloadPlugin(byteArray, fullname, finish, onerror) {
        if (typeof Browser != "undefined") Browser.init();
        var handled = false;
        preloadPlugins.forEach(function(plugin) {
          if (handled) return;
          if (plugin["canHandle"](fullname)) {
            plugin["handle"](byteArray, fullname, finish, onerror);
            handled = true
          }
        });
        return handled
      }

      function FS_createPreloadedFile(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile,
        canOwn, preFinish) {
        var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent;
        var dep = getUniqueRunDependency(`cp ${fullname}`);

        function processData(byteArray) {
          function finish(byteArray) {
            if (preFinish) preFinish();
            if (!dontCreateFile) {
              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn)
            }
            if (onload) onload();
            removeRunDependency(dep)
          }
          if (FS_handledByPreloadPlugin(byteArray, fullname, finish, () => {
              if (onerror) onerror();
              removeRunDependency(dep)
            })) {
            return
          }
          finish(byteArray)
        }
        addRunDependency(dep);
        if (typeof url == "string") {
          asyncLoad(url, byteArray => processData(byteArray), onerror)
        } else {
          processData(url)
        }
      }

      function FS_modeStringToFlags(str) {
        var flagModes = {
          "r": 0,
          "r+": 2,
          "w": 512 | 64 | 1,
          "w+": 512 | 64 | 2,
          "a": 1024 | 64 | 1,
          "a+": 1024 | 64 | 2
        };
        var flags = flagModes[str];
        if (typeof flags == "undefined") {
          throw new Error(`Unknown file open mode: ${str}`)
        }
        return flags
      }

      function FS_getMode(canRead, canWrite) {
        var mode = 0;
        if (canRead) mode |= 292 | 73;
        if (canWrite) mode |= 146;
        return mode
      }
      var FS = {
        root: null,
        mounts: [],
        devices: {},
        streams: [],
        nextInode: 1,
        nameTable: null,
        currentPath: "/",
        initialized: false,
        ignorePermissions: true,
        ErrnoError: null,
        genericErrors: {},
        filesystems: null,
        syncFSRequests: 0,
        lookupPath: (path, opts = {}) => {
          path = PATH_FS.resolve(path);
          if (!path) return {
            path: "",
            node: null
          };
          var defaults = {
            follow_mount: true,
            recurse_count: 0
          };
          opts = Object.assign(defaults, opts);
          if (opts.recurse_count > 8) {
            throw new FS.ErrnoError(32)
          }
          var parts = path.split("/").filter(p => !!p);
          var current = FS.root;
          var current_path = "/";
          for (var i = 0; i < parts.length; i++) {
            var islast = i === parts.length - 1;
            if (islast && opts.parent) {
              break
            }
            current = FS.lookupNode(current, parts[i]);
            current_path = PATH.join2(current_path, parts[i]);
            if (FS.isMountpoint(current)) {
              if (!islast || islast && opts.follow_mount) {
                current = current.mounted.root
              }
            }
            if (!islast || opts.follow) {
              var count = 0;
              while (FS.isLink(current.mode)) {
                var link = FS.readlink(current_path);
                current_path = PATH_FS.resolve(PATH.dirname(current_path), link);
                var lookup = FS.lookupPath(current_path, {
                  recurse_count: opts.recurse_count + 1
                });
                current = lookup.node;
                if (count++ > 40) {
                  throw new FS.ErrnoError(32)
                }
              }
            }
          }
          return {
            path: current_path,
            node: current
          }
        },
        getPath: node => {
          var path;
          while (true) {
            if (FS.isRoot(node)) {
              var mount = node.mount.mountpoint;
              if (!path) return mount;
              return mount[mount.length - 1] !== "/" ? `${mount}/${path}` : mount + path
            }
            path = path ? `${node.name}/${path}` : node.name;
            node = node.parent
          }
        },
        hashName: (parentid, name) => {
          var hash = 0;
          for (var i = 0; i < name.length; i++) {
            hash = (hash << 5) - hash + name.charCodeAt(i) | 0
          }
          return (parentid + hash >>> 0) % FS.nameTable.length
        },
        hashAddNode: node => {
          var hash = FS.hashName(node.parent.id, node.name);
          node.name_next = FS.nameTable[hash];
          FS.nameTable[hash] = node
        },
        hashRemoveNode: node => {
          var hash = FS.hashName(node.parent.id, node.name);
          if (FS.nameTable[hash] === node) {
            FS.nameTable[hash] = node.name_next
          } else {
            var current = FS.nameTable[hash];
            while (current) {
              if (current.name_next === node) {
                current.name_next = node.name_next;
                break
              }
              current = current.name_next
            }
          }
        },
        lookupNode: (parent, name) => {
          var errCode = FS.mayLookup(parent);
          if (errCode) {
            throw new FS.ErrnoError(errCode, parent)
          }
          var hash = FS.hashName(parent.id, name);
          for (var node = FS.nameTable[hash]; node; node = node.name_next) {
            var nodeName = node.name;
            if (node.parent.id === parent.id && nodeName === name) {
              return node
            }
          }
          return FS.lookup(parent, name)
        },
        createNode: (parent, name, mode, rdev) => {
          var node = new FS.FSNode(parent, name, mode, rdev);
          FS.hashAddNode(node);
          return node
        },
        destroyNode: node => {
          FS.hashRemoveNode(node)
        },
        isRoot: node => {
          return node === node.parent
        },
        isMountpoint: node => {
          return !!node.mounted
        },
        isFile: mode => {
          return (mode & 61440) === 32768
        },
        isDir: mode => {
          return (mode & 61440) === 16384
        },
        isLink: mode => {
          return (mode & 61440) === 40960
        },
        isChrdev: mode => {
          return (mode & 61440) === 8192
        },
        isBlkdev: mode => {
          return (mode & 61440) === 24576
        },
        isFIFO: mode => {
          return (mode & 61440) === 4096
        },
        isSocket: mode => {
          return (mode & 49152) === 49152
        },
        flagsToPermissionString: flag => {
          var perms = ["r", "w", "rw"][flag & 3];
          if (flag & 512) {
            perms += "w"
          }
          return perms
        },
        nodePermissions: (node, perms) => {
          if (FS.ignorePermissions) {
            return 0
          }
          if (perms.includes("r") && !(node.mode & 292)) {
            return 2
          } else if (perms.includes("w") && !(node.mode & 146)) {
            return 2
          } else if (perms.includes("x") && !(node.mode & 73)) {
            return 2
          }
          return 0
        },
        mayLookup: dir => {
          var errCode = FS.nodePermissions(dir, "x");
          if (errCode) return errCode;
          if (!dir.node_ops.lookup) return 2;
          return 0
        },
        mayCreate: (dir, name) => {
          try {
            var node = FS.lookupNode(dir, name);
            return 20
          } catch (e) {}
          return FS.nodePermissions(dir, "wx")
        },
        mayDelete: (dir, name, isdir) => {
          var node;
          try {
            node = FS.lookupNode(dir, name)
          } catch (e) {
            return e.errno
          }
          var errCode = FS.nodePermissions(dir, "wx");
          if (errCode) {
            return errCode
          }
          if (isdir) {
            if (!FS.isDir(node.mode)) {
              return 54
            }
            if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
              return 10
            }
          } else {
            if (FS.isDir(node.mode)) {
              return 31
            }
          }
          return 0
        },
        mayOpen: (node, flags) => {
          if (!node) {
            return 44
          }
          if (FS.isLink(node.mode)) {
            return 32
          } else if (FS.isDir(node.mode)) {
            if (FS.flagsToPermissionString(flags) !== "r" || flags & 512) {
              return 31
            }
          }
          return FS.nodePermissions(node, FS.flagsToPermissionString(flags))
        },
        MAX_OPEN_FDS: 4096,
        nextfd: () => {
          for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) {
            if (!FS.streams[fd]) {
              return fd
            }
          }
          throw new FS.ErrnoError(33)
        },
        getStreamChecked: fd => {
          var stream = FS.getStream(fd);
          if (!stream) {
            throw new FS.ErrnoError(8)
          }
          return stream
        },
        getStream: fd => FS.streams[fd],
        createStream: (stream, fd = -1) => {
          if (!FS.FSStream) {
            FS.FSStream = function() {
              this.shared = {}
            };
            FS.FSStream.prototype = {};
            Object.defineProperties(FS.FSStream.prototype, {
              object: {
                get: function() {
                  return this.node
                },
                set: function(val) {
                  this.node = val
                }
              },
              isRead: {
                get: function() {
                  return (this.flags & 2097155) !== 1
                }
              },
              isWrite: {
                get: function() {
                  return (this.flags & 2097155) !== 0
                }
              },
              isAppend: {
                get: function() {
                  return this.flags & 1024
                }
              },
              flags: {
                get: function() {
                  return this.shared.flags
                },
                set: function(val) {
                  this.shared.flags = val
                }
              },
              position: {
                get: function() {
                  return this.shared.position
                },
                set: function(val) {
                  this.shared.position = val
                }
              }
            })
          }
          stream = Object.assign(new FS.FSStream, stream);
          if (fd == -1) {
            fd = FS.nextfd()
          }
          stream.fd = fd;
          FS.streams[fd] = stream;
          return stream
        },
        closeStream: fd => {
          FS.streams[fd] = null
        },
        chrdev_stream_ops: {
          open: stream => {
            var device = FS.getDevice(stream.node.rdev);
            stream.stream_ops = device.stream_ops;
            if (stream.stream_ops.open) {
              stream.stream_ops.open(stream)
            }
          },
          llseek: () => {
            throw new FS.ErrnoError(70)
          }
        },
        major: dev => dev >> 8,
        minor: dev => dev & 255,
        makedev: (ma, mi) => ma << 8 | mi,
        registerDevice: (dev, ops) => {
          FS.devices[dev] = {
            stream_ops: ops
          }
        },
        getDevice: dev => FS.devices[dev],
        getMounts: mount => {
          var mounts = [];
          var check = [mount];
          while (check.length) {
            var m = check.pop();
            mounts.push(m);
            check.push.apply(check, m.mounts)
          }
          return mounts
        },
        syncfs: (populate, callback) => {
          if (typeof populate == "function") {
            callback = populate;
            populate = false
          }
          FS.syncFSRequests++;
          if (FS.syncFSRequests > 1) {
            err(
              `warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)
          }
          var mounts = FS.getMounts(FS.root.mount);
          var completed = 0;

          function doCallback(errCode) {
            FS.syncFSRequests--;
            return callback(errCode)
          }

          function done(errCode) {
            if (errCode) {
              if (!done.errored) {
                done.errored = true;
                return doCallback(errCode)
              }
              return
            }
            if (++completed >= mounts.length) {
              doCallback(null)
            }
          }
          mounts.forEach(mount => {
            if (!mount.type.syncfs) {
              return done(null)
            }
            mount.type.syncfs(mount, populate, done)
          })
        },
        mount: (type, opts, mountpoint) => {
          var root = mountpoint === "/";
          var pseudo = !mountpoint;
          var node;
          if (root && FS.root) {
            throw new FS.ErrnoError(10)
          } else if (!root && !pseudo) {
            var lookup = FS.lookupPath(mountpoint, {
              follow_mount: false
            });
            mountpoint = lookup.path;
            node = lookup.node;
            if (FS.isMountpoint(node)) {
              throw new FS.ErrnoError(10)
            }
            if (!FS.isDir(node.mode)) {
              throw new FS.ErrnoError(54)
            }
          }
          var mount = {
            type: type,
            opts: opts,
            mountpoint: mountpoint,
            mounts: []
          };
          var mountRoot = type.mount(mount);
          mountRoot.mount = mount;
          mount.root = mountRoot;
          if (root) {
            FS.root = mountRoot
          } else if (node) {
            node.mounted = mount;
            if (node.mount) {
              node.mount.mounts.push(mount)
            }
          }
          return mountRoot
        },
        unmount: mountpoint => {
          var lookup = FS.lookupPath(mountpoint, {
            follow_mount: false
          });
          if (!FS.isMountpoint(lookup.node)) {
            throw new FS.ErrnoError(28)
          }
          var node = lookup.node;
          var mount = node.mounted;
          var mounts = FS.getMounts(mount);
          Object.keys(FS.nameTable).forEach(hash => {
            var current = FS.nameTable[hash];
            while (current) {
              var next = current.name_next;
              if (mounts.includes(current.mount)) {
                FS.destroyNode(current)
              }
              current = next
            }
          });
          node.mounted = null;
          var idx = node.mount.mounts.indexOf(mount);
          node.mount.mounts.splice(idx, 1)
        },
        lookup: (parent, name) => {
          return parent.node_ops.lookup(parent, name)
        },
        mknod: (path, mode, dev) => {
          var lookup = FS.lookupPath(path, {
            parent: true
          });
          var parent = lookup.node;
          var name = PATH.basename(path);
          if (!name || name === "." || name === "..") {
            throw new FS.ErrnoError(28)
          }
          var errCode = FS.mayCreate(parent, name);
          if (errCode) {
            throw new FS.ErrnoError(errCode)
          }
          if (!parent.node_ops.mknod) {
            throw new FS.ErrnoError(63)
          }
          return parent.node_ops.mknod(parent, name, mode, dev)
        },
        create: (path, mode) => {
          mode = mode !== undefined ? mode : 438;
          mode &= 4095;
          mode |= 32768;
          return FS.mknod(path, mode, 0)
        },
        mkdir: (path, mode) => {
          mode = mode !== undefined ? mode : 511;
          mode &= 511 | 512;
          mode |= 16384;
          return FS.mknod(path, mode, 0)
        },
        mkdirTree: (path, mode) => {
          var dirs = path.split("/");
          var d = "";
          for (var i = 0; i < dirs.length; ++i) {
            if (!dirs[i]) continue;
            d += "/" + dirs[i];
            try {
              FS.mkdir(d, mode)
            } catch (e) {
              if (e.errno != 20) throw e
            }
          }
        },
        mkdev: (path, mode, dev) => {
          if (typeof dev == "undefined") {
            dev = mode;
            mode = 438
          }
          mode |= 8192;
          return FS.mknod(path, mode, dev)
        },
        symlink: (oldpath, newpath) => {
          if (!PATH_FS.resolve(oldpath)) {
            throw new FS.ErrnoError(44)
          }
          var lookup = FS.lookupPath(newpath, {
            parent: true
          });
          var parent = lookup.node;
          if (!parent) {
            throw new FS.ErrnoError(44)
          }
          var newname = PATH.basename(newpath);
          var errCode = FS.mayCreate(parent, newname);
          if (errCode) {
            throw new FS.ErrnoError(errCode)
          }
          if (!parent.node_ops.symlink) {
            throw new FS.ErrnoError(63)
          }
          return parent.node_ops.symlink(parent, newname, oldpath)
        },
        rename: (old_path, new_path) => {
          var old_dirname = PATH.dirname(old_path);
          var new_dirname = PATH.dirname(new_path);
          var old_name = PATH.basename(old_path);
          var new_name = PATH.basename(new_path);
          var lookup, old_dir, new_dir;
          lookup = FS.lookupPath(old_path, {
            parent: true
          });
          old_dir = lookup.node;
          lookup = FS.lookupPath(new_path, {
            parent: true
          });
          new_dir = lookup.node;
          if (!old_dir || !new_dir) throw new FS.ErrnoError(44);
          if (old_dir.mount !== new_dir.mount) {
            throw new FS.ErrnoError(75)
          }
          var old_node = FS.lookupNode(old_dir, old_name);
          var relative = PATH_FS.relative(old_path, new_dirname);
          if (relative.charAt(0) !== ".") {
            throw new FS.ErrnoError(28)
          }
          relative = PATH_FS.relative(new_path, old_dirname);
          if (relative.charAt(0) !== ".") {
            throw new FS.ErrnoError(55)
          }
          var new_node;
          try {
            new_node = FS.lookupNode(new_dir, new_name)
          } catch (e) {}
          if (old_node === new_node) {
            return
          }
          var isdir = FS.isDir(old_node.mode);
          var errCode = FS.mayDelete(old_dir, old_name, isdir);
          if (errCode) {
            throw new FS.ErrnoError(errCode)
          }
          errCode = new_node ? FS.mayDelete(new_dir, new_name, isdir) : FS.mayCreate(new_dir, new_name);
          if (errCode) {
            throw new FS.ErrnoError(errCode)
          }
          if (!old_dir.node_ops.rename) {
            throw new FS.ErrnoError(63)
          }
          if (FS.isMountpoint(old_node) || new_node && FS.isMountpoint(new_node)) {
            throw new FS.ErrnoError(10)
          }
          if (new_dir !== old_dir) {
            errCode = FS.nodePermissions(old_dir, "w");
            if (errCode) {
              throw new FS.ErrnoError(errCode)
            }
          }
          FS.hashRemoveNode(old_node);
          try {
            old_dir.node_ops.rename(old_node, new_dir, new_name)
          } catch (e) {
            throw e
          } finally {
            FS.hashAddNode(old_node)
          }
        },
        rmdir: path => {
          var lookup = FS.lookupPath(path, {
            parent: true
          });
          var parent = lookup.node;
          var name = PATH.basename(path);
          var node = FS.lookupNode(parent, name);
          var errCode = FS.mayDelete(parent, name, true);
          if (errCode) {
            throw new FS.ErrnoError(errCode)
          }
          if (!parent.node_ops.rmdir) {
            throw new FS.ErrnoError(63)
          }
          if (FS.isMountpoint(node)) {
            throw new FS.ErrnoError(10)
          }
          parent.node_ops.rmdir(parent, name);
          FS.destroyNode(node)
        },
        readdir: path => {
          var lookup = FS.lookupPath(path, {
            follow: true
          });
          var node = lookup.node;
          if (!node.node_ops.readdir) {
            throw new FS.ErrnoError(54)
          }
          return node.node_ops.readdir(node)
        },
        unlink: path => {
          var lookup = FS.lookupPath(path, {
            parent: true
          });
          var parent = lookup.node;
          if (!parent) {
            throw new FS.ErrnoError(44)
          }
          var name = PATH.basename(path);
          var node = FS.lookupNode(parent, name);
          var errCode = FS.mayDelete(parent, name, false);
          if (errCode) {
            throw new FS.ErrnoError(errCode)
          }
          if (!parent.node_ops.unlink) {
            throw new FS.ErrnoError(63)
          }
          if (FS.isMountpoint(node)) {
            throw new FS.ErrnoError(10)
          }
          parent.node_ops.unlink(parent, name);
          FS.destroyNode(node)
        },
        readlink: path => {
          var lookup = FS.lookupPath(path);
          var link = lookup.node;
          if (!link) {
            throw new FS.ErrnoError(44)
          }
          if (!link.node_ops.readlink) {
            throw new FS.ErrnoError(28)
          }
          return PATH_FS.resolve(FS.getPath(link.parent), link.node_ops.readlink(link))
        },
        stat: (path, dontFollow) => {
          var lookup = FS.lookupPath(path, {
            follow: !dontFollow
          });
          var node = lookup.node;
          if (!node) {
            throw new FS.ErrnoError(44)
          }
          if (!node.node_ops.getattr) {
            throw new FS.ErrnoError(63)
          }
          return node.node_ops.getattr(node)
        },
        lstat: path => {
          return FS.stat(path, true)
        },
        chmod: (path, mode, dontFollow) => {
          var node;
          if (typeof path == "string") {
            var lookup = FS.lookupPath(path, {
              follow: !dontFollow
            });
            node = lookup.node
          } else {
            node = path
          }
          if (!node.node_ops.setattr) {
            throw new FS.ErrnoError(63)
          }
          node.node_ops.setattr(node, {
            mode: mode & 4095 | node.mode & ~4095,
            timestamp: Date.now()
          })
        },
        lchmod: (path, mode) => {
          FS.chmod(path, mode, true)
        },
        fchmod: (fd, mode) => {
          var stream = FS.getStreamChecked(fd);
          FS.chmod(stream.node, mode)
        },
        chown: (path, uid, gid, dontFollow) => {
          var node;
          if (typeof path == "string") {
            var lookup = FS.lookupPath(path, {
              follow: !dontFollow
            });
            node = lookup.node
          } else {
            node = path
          }
          if (!node.node_ops.setattr) {
            throw new FS.ErrnoError(63)
          }
          node.node_ops.setattr(node, {
            timestamp: Date.now()
          })
        },
        lchown: (path, uid, gid) => {
          FS.chown(path, uid, gid, true)
        },
        fchown: (fd, uid, gid) => {
          var stream = FS.getStreamChecked(fd);
          FS.chown(stream.node, uid, gid)
        },
        truncate: (path, len) => {
          if (len < 0) {
            throw new FS.ErrnoError(28)
          }
          var node;
          if (typeof path == "string") {
            var lookup = FS.lookupPath(path, {
              follow: true
            });
            node = lookup.node
          } else {
            node = path
          }
          if (!node.node_ops.setattr) {
            throw new FS.ErrnoError(63)
          }
          if (FS.isDir(node.mode)) {
            throw new FS.ErrnoError(31)
          }
          if (!FS.isFile(node.mode)) {
            throw new FS.ErrnoError(28)
          }
          var errCode = FS.nodePermissions(node, "w");
          if (errCode) {
            throw new FS.ErrnoError(errCode)
          }
          node.node_ops.setattr(node, {
            size: len,
            timestamp: Date.now()
          })
        },
        ftruncate: (fd, len) => {
          var stream = FS.getStreamChecked(fd);
          if ((stream.flags & 2097155) === 0) {
            throw new FS.ErrnoError(28)
          }
          FS.truncate(stream.node, len)
        },
        utime: (path, atime, mtime) => {
          var lookup = FS.lookupPath(path, {
            follow: true
          });
          var node = lookup.node;
          node.node_ops.setattr(node, {
            timestamp: Math.max(atime, mtime)
          })
        },
        open: (path, flags, mode) => {
          if (path === "") {
            throw new FS.ErrnoError(44)
          }
          flags = typeof flags == "string" ? FS_modeStringToFlags(flags) : flags;
          mode = typeof mode == "undefined" ? 438 : mode;
          if (flags & 64) {
            mode = mode & 4095 | 32768
          } else {
            mode = 0
          }
          var node;
          if (typeof path == "object") {
            node = path
          } else {
            path = PATH.normalize(path);
            try {
              var lookup = FS.lookupPath(path, {
                follow: !(flags & 131072)
              });
              node = lookup.node
            } catch (e) {}
          }
          var created = false;
          if (flags & 64) {
            if (node) {
              if (flags & 128) {
                throw new FS.ErrnoError(20)
              }
            } else {
              node = FS.mknod(path, mode, 0);
              created = true
            }
          }
          if (!node) {
            throw new FS.ErrnoError(44)
          }
          if (FS.isChrdev(node.mode)) {
            flags &= ~512
          }
          if (flags & 65536 && !FS.isDir(node.mode)) {
            throw new FS.ErrnoError(54)
          }
          if (!created) {
            var errCode = FS.mayOpen(node, flags);
            if (errCode) {
              throw new FS.ErrnoError(errCode)
            }
          }
          if (flags & 512 && !created) {
            FS.truncate(node, 0)
          }
          flags &= ~(128 | 512 | 131072);
          var stream = FS.createStream({
            node: node,
            path: FS.getPath(node),
            flags: flags,
            seekable: true,
            position: 0,
            stream_ops: node.stream_ops,
            ungotten: [],
            error: false
          });
          if (stream.stream_ops.open) {
            stream.stream_ops.open(stream)
          }
          if (Module["logReadFiles"] && !(flags & 1)) {
            if (!FS.readFiles) FS.readFiles = {};
            if (!(path in FS.readFiles)) {
              FS.readFiles[path] = 1
            }
          }
          return stream
        },
        close: stream => {
          if (FS.isClosed(stream)) {
            throw new FS.ErrnoError(8)
          }
          if (stream.getdents) stream.getdents = null;
          try {
            if (stream.stream_ops.close) {
              stream.stream_ops.close(stream)
            }
          } catch (e) {
            throw e
          } finally {
            FS.closeStream(stream.fd)
          }
          stream.fd = null
        },
        isClosed: stream => {
          return stream.fd === null
        },
        llseek: (stream, offset, whence) => {
          if (FS.isClosed(stream)) {
            throw new FS.ErrnoError(8)
          }
          if (!stream.seekable || !stream.stream_ops.llseek) {
            throw new FS.ErrnoError(70)
          }
          if (whence != 0 && whence != 1 && whence != 2) {
            throw new FS.ErrnoError(28)
          }
          stream.position = stream.stream_ops.llseek(stream, offset, whence);
          stream.ungotten = [];
          return stream.position
        },
        read: (stream, buffer, offset, length, position) => {
          if (length < 0 || position < 0) {
            throw new FS.ErrnoError(28)
          }
          if (FS.isClosed(stream)) {
            throw new FS.ErrnoError(8)
          }
          if ((stream.flags & 2097155) === 1) {
            throw new FS.ErrnoError(8)
          }
          if (FS.isDir(stream.node.mode)) {
            throw new FS.ErrnoError(31)
          }
          if (!stream.stream_ops.read) {
            throw new FS.ErrnoError(28)
          }
          var seeking = typeof position != "undefined";
          if (!seeking) {
            position = stream.position
          } else if (!stream.seekable) {
            throw new FS.ErrnoError(70)
          }
          var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
          if (!seeking) stream.position += bytesRead;
          return bytesRead
        },
        write: (stream, buffer, offset, length, position, canOwn) => {
          if (length < 0 || position < 0) {
            throw new FS.ErrnoError(28)
          }
          if (FS.isClosed(stream)) {
            throw new FS.ErrnoError(8)
          }
          if ((stream.flags & 2097155) === 0) {
            throw new FS.ErrnoError(8)
          }
          if (FS.isDir(stream.node.mode)) {
            throw new FS.ErrnoError(31)
          }
          if (!stream.stream_ops.write) {
            throw new FS.ErrnoError(28)
          }
          if (stream.seekable && stream.flags & 1024) {
            FS.llseek(stream, 0, 2)
          }
          var seeking = typeof position != "undefined";
          if (!seeking) {
            position = stream.position
          } else if (!stream.seekable) {
            throw new FS.ErrnoError(70)
          }
          var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
          if (!seeking) stream.position += bytesWritten;
          return bytesWritten
        },
        allocate: (stream, offset, length) => {
          if (FS.isClosed(stream)) {
            throw new FS.ErrnoError(8)
          }
          if (offset < 0 || length <= 0) {
            throw new FS.ErrnoError(28)
          }
          if ((stream.flags & 2097155) === 0) {
            throw new FS.ErrnoError(8)
          }
          if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {
            throw new FS.ErrnoError(43)
          }
          if (!stream.stream_ops.allocate) {
            throw new FS.ErrnoError(138)
          }
          stream.stream_ops.allocate(stream, offset, length)
        },
        mmap: (stream, length, position, prot, flags) => {
          if ((prot & 2) !== 0 && (flags & 2) === 0 && (stream.flags & 2097155) !== 2) {
            throw new FS.ErrnoError(2)
          }
          if ((stream.flags & 2097155) === 1) {
            throw new FS.ErrnoError(2)
          }
          if (!stream.stream_ops.mmap) {
            throw new FS.ErrnoError(43)
          }
          return stream.stream_ops.mmap(stream, length, position, prot, flags)
        },
        msync: (stream, buffer, offset, length, mmapFlags) => {
          if (!stream.stream_ops.msync) {
            return 0
          }
          return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags)
        },
        munmap: stream => 0,
        ioctl: (stream, cmd, arg) => {
          if (!stream.stream_ops.ioctl) {
            throw new FS.ErrnoError(59)
          }
          return stream.stream_ops.ioctl(stream, cmd, arg)
        },
        readFile: (path, opts = {}) => {
          opts.flags = opts.flags || 0;
          opts.encoding = opts.encoding || "binary";
          if (opts.encoding !== "utf8" && opts.encoding !== "binary") {
            throw new Error(`Invalid encoding type "${opts.encoding}"`)
          }
          var ret;
          var stream = FS.open(path, opts.flags);
          var stat = FS.stat(path);
          var length = stat.size;
          var buf = new Uint8Array(length);
          FS.read(stream, buf, 0, length, 0);
          if (opts.encoding === "utf8") {
            ret = UTF8ArrayToString(buf, 0)
          } else if (opts.encoding === "binary") {
            ret = buf
          }
          FS.close(stream);
          return ret
        },
        writeFile: (path, data, opts = {}) => {
          opts.flags = opts.flags || 577;
          var stream = FS.open(path, opts.flags, opts.mode);
          if (typeof data == "string") {
            var buf = new Uint8Array(lengthBytesUTF8(data) + 1);
            var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length);
            FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn)
          } else if (ArrayBuffer.isView(data)) {
            FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn)
          } else {
            throw new Error("Unsupported data type")
          }
          FS.close(stream)
        },
        cwd: () => FS.currentPath,
        chdir: path => {
          var lookup = FS.lookupPath(path, {
            follow: true
          });
          if (lookup.node === null) {
            throw new FS.ErrnoError(44)
          }
          if (!FS.isDir(lookup.node.mode)) {
            throw new FS.ErrnoError(54)
          }
          var errCode = FS.nodePermissions(lookup.node, "x");
          if (errCode) {
            throw new FS.ErrnoError(errCode)
          }
          FS.currentPath = lookup.path
        },
        createDefaultDirectories: () => {
          FS.mkdir("/tmp");
          FS.mkdir("/home");
          FS.mkdir("/home/web_user")
        },
        createDefaultDevices: () => {
          FS.mkdir("/dev");
          FS.registerDevice(FS.makedev(1, 3), {
            read: () => 0,
            write: (stream, buffer, offset, length, pos) => length
          });
          FS.mkdev("/dev/null", FS.makedev(1, 3));
          TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
          TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
          FS.mkdev("/dev/tty", FS.makedev(5, 0));
          FS.mkdev("/dev/tty1", FS.makedev(6, 0));
          var randomBuffer = new Uint8Array(1024),
            randomLeft = 0;
          var randomByte = () => {
            if (randomLeft === 0) {
              randomLeft = randomFill(randomBuffer).byteLength
            }
            return randomBuffer[--randomLeft]
          };
          FS.createDevice("/dev", "random", randomByte);
          FS.createDevice("/dev", "urandom", randomByte);
          FS.mkdir("/dev/shm");
          FS.mkdir("/dev/shm/tmp")
        },
        createSpecialDirectories: () => {
          FS.mkdir("/proc");
          var proc_self = FS.mkdir("/proc/self");
          FS.mkdir("/proc/self/fd");
          FS.mount({
            mount: () => {
              var node = FS.createNode(proc_self, "fd", 16384 | 511, 73);
              node.node_ops = {
                lookup: (parent, name) => {
                  var fd = +name;
                  var stream = FS.getStreamChecked(fd);
                  var ret = {
                    parent: null,
                    mount: {
                      mountpoint: "fake"
                    },
                    node_ops: {
                      readlink: () => stream.path
                    }
                  };
                  ret.parent = ret;
                  return ret
                }
              };
              return node
            }
          }, {}, "/proc/self/fd")
        },
        createStandardStreams: () => {
          if (Module["stdin"]) {
            FS.createDevice("/dev", "stdin", Module["stdin"])
          } else {
            FS.symlink("/dev/tty", "/dev/stdin")
          }
          if (Module["stdout"]) {
            FS.createDevice("/dev", "stdout", null, Module["stdout"])
          } else {
            FS.symlink("/dev/tty", "/dev/stdout")
          }
          if (Module["stderr"]) {
            FS.createDevice("/dev", "stderr", null, Module["stderr"])
          } else {
            FS.symlink("/dev/tty1", "/dev/stderr")
          }
          var stdin = FS.open("/dev/stdin", 0);
          var stdout = FS.open("/dev/stdout", 1);
          var stderr = FS.open("/dev/stderr", 1)
        },
        ensureErrnoError: () => {
          if (FS.ErrnoError) return;
          FS.ErrnoError = function ErrnoError(errno, node) {
            this.name = "ErrnoError";
            this.node = node;
            this.setErrno = function(errno) {
              this.errno = errno
            };
            this.setErrno(errno);
            this.message = "FS error"
          };
          FS.ErrnoError.prototype = new Error;
          FS.ErrnoError.prototype.constructor = FS.ErrnoError;
          [44].forEach(code => {
            FS.genericErrors[code] = new FS.ErrnoError(code);
            FS.genericErrors[code].stack = "<generic error, no stack>"
          })
        },
        staticInit: () => {
          FS.ensureErrnoError();
          FS.nameTable = new Array(4096);
          FS.mount(MEMFS, {}, "/");
          FS.createDefaultDirectories();
          FS.createDefaultDevices();
          FS.createSpecialDirectories();
          FS.filesystems = {
            "MEMFS": MEMFS
          }
        },
        init: (input, output, error) => {
          FS.init.initialized = true;
          FS.ensureErrnoError();
          Module["stdin"] = input || Module["stdin"];
          Module["stdout"] = output || Module["stdout"];
          Module["stderr"] = error || Module["stderr"];
          FS.createStandardStreams()
        },
        quit: () => {
          FS.init.initialized = false;
          for (var i = 0; i < FS.streams.length; i++) {
            var stream = FS.streams[i];
            if (!stream) {
              continue
            }
            FS.close(stream)
          }
        },
        findObject: (path, dontResolveLastLink) => {
          var ret = FS.analyzePath(path, dontResolveLastLink);
          if (!ret.exists) {
            return null
          }
          return ret.object
        },
        analyzePath: (path, dontResolveLastLink) => {
          try {
            var lookup = FS.lookupPath(path, {
              follow: !dontResolveLastLink
            });
            path = lookup.path
          } catch (e) {}
          var ret = {
            isRoot: false,
            exists: false,
            error: 0,
            name: null,
            path: null,
            object: null,
            parentExists: false,
            parentPath: null,
            parentObject: null
          };
          try {
            var lookup = FS.lookupPath(path, {
              parent: true
            });
            ret.parentExists = true;
            ret.parentPath = lookup.path;
            ret.parentObject = lookup.node;
            ret.name = PATH.basename(path);
            lookup = FS.lookupPath(path, {
              follow: !dontResolveLastLink
            });
            ret.exists = true;
            ret.path = lookup.path;
            ret.object = lookup.node;
            ret.name = lookup.node.name;
            ret.isRoot = lookup.path === "/"
          } catch (e) {
            ret.error = e.errno
          }
          return ret
        },
        createPath: (parent, path, canRead, canWrite) => {
          parent = typeof parent == "string" ? parent : FS.getPath(parent);
          var parts = path.split("/").reverse();
          while (parts.length) {
            var part = parts.pop();
            if (!part) continue;
            var current = PATH.join2(parent, part);
            try {
              FS.mkdir(current)
            } catch (e) {}
            parent = current
          }
          return current
        },
        createFile: (parent, name, properties, canRead, canWrite) => {
          var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name);
          var mode = FS_getMode(canRead, canWrite);
          return FS.create(path, mode)
        },
        createDataFile: (parent, name, data, canRead, canWrite, canOwn) => {
          var path = name;
          if (parent) {
            parent = typeof parent == "string" ? parent : FS.getPath(parent);
            path = name ? PATH.join2(parent, name) : parent
          }
          var mode = FS_getMode(canRead, canWrite);
          var node = FS.create(path, mode);
          if (data) {
            if (typeof data == "string") {
              var arr = new Array(data.length);
              for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
              data = arr
            }
            FS.chmod(node, mode | 146);
            var stream = FS.open(node, 577);
            FS.write(stream, data, 0, data.length, 0, canOwn);
            FS.close(stream);
            FS.chmod(node, mode)
          }
          return node
        },
        createDevice: (parent, name, input, output) => {
          var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name);
          var mode = FS_getMode(!!input, !!output);
          if (!FS.createDevice.major) FS.createDevice.major = 64;
          var dev = FS.makedev(FS.createDevice.major++, 0);
          FS.registerDevice(dev, {
            open: stream => {
              stream.seekable = false
            },
            close: stream => {
              if (output && output.buffer && output.buffer.length) {
                output(10)
              }
            },
            read: (stream, buffer, offset, length, pos) => {
              var bytesRead = 0;
              for (var i = 0; i < length; i++) {
                var result;
                try {
                  result = input()
                } catch (e) {
                  throw new FS.ErrnoError(29)
                }
                if (result === undefined && bytesRead === 0) {
                  throw new FS.ErrnoError(6)
                }
                if (result === null || result === undefined) break;
                bytesRead++;
                buffer[offset + i] = result
              }
              if (bytesRead) {
                stream.node.timestamp = Date.now()
              }
              return bytesRead
            },
            write: (stream, buffer, offset, length, pos) => {
              for (var i = 0; i < length; i++) {
                try {
                  output(buffer[offset + i])
                } catch (e) {
                  throw new FS.ErrnoError(29)
                }
              }
              if (length) {
                stream.node.timestamp = Date.now()
              }
              return i
            }
          });
          return FS.mkdev(path, mode, dev)
        },
        forceLoadFile: obj => {
          if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
          if (typeof XMLHttpRequest != "undefined") {
            throw new Error(
              "Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread."
              )
          } else if (read_) {
            try {
              obj.contents = intArrayFromString(read_(obj.url), true);
              obj.usedBytes = obj.contents.length
            } catch (e) {
              throw new FS.ErrnoError(29)
            }
          } else {
            throw new Error("Cannot load without read() or XMLHttpRequest.")
          }
        },
        createLazyFile: (parent, name, url, canRead, canWrite) => {
          function LazyUint8Array() {
            this.lengthKnown = false;
            this.chunks = []
          }
          LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
            if (idx > this.length - 1 || idx < 0) {
              return undefined
            }
            var chunkOffset = idx % this.chunkSize;
            var chunkNum = idx / this.chunkSize | 0;
            return this.getter(chunkNum)[chunkOffset]
          };
          LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
            this.getter = getter
          };
          LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
            var xhr = new XMLHttpRequest;
            xhr.open("HEAD", url, false);
            xhr.send(null);
            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error(
              "Couldn't load " + url + ". Status: " + xhr.status);
            var datalength = Number(xhr.getResponseHeader("Content-length"));
            var header;
            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
            var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip";
            var chunkSize = 1024 * 1024;
            if (!hasByteServing) chunkSize = datalength;
            var doXHR = (from, to) => {
              if (from > to) throw new Error("invalid range (" + from + ", " + to +
                ") or no bytes requested!");
              if (to > datalength - 1) throw new Error("only " + datalength +
                " bytes available! programmer error!");
              var xhr = new XMLHttpRequest;
              xhr.open("GET", url, false);
              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
              xhr.responseType = "arraybuffer";
              if (xhr.overrideMimeType) {
                xhr.overrideMimeType("text/plain; charset=x-user-defined")
              }
              xhr.send(null);
              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error(
                "Couldn't load " + url + ". Status: " + xhr.status);
              if (xhr.response !== undefined) {
                return new Uint8Array(xhr.response || [])
              }
              return intArrayFromString(xhr.responseText || "", true)
            };
            var lazyArray = this;
            lazyArray.setDataGetter(chunkNum => {
              var start = chunkNum * chunkSize;
              var end = (chunkNum + 1) * chunkSize - 1;
              end = Math.min(end, datalength - 1);
              if (typeof lazyArray.chunks[chunkNum] == "undefined") {
                lazyArray.chunks[chunkNum] = doXHR(start, end)
              }
              if (typeof lazyArray.chunks[chunkNum] == "undefined") throw new Error("doXHR failed!");
              return lazyArray.chunks[chunkNum]
            });
            if (usesGzip || !datalength) {
              chunkSize = datalength = 1;
              datalength = this.getter(0).length;
              chunkSize = datalength;
              out("LazyFiles on gzip forces download of the whole file when length is accessed")
            }
            this._length = datalength;
            this._chunkSize = chunkSize;
            this.lengthKnown = true
          };
          if (typeof XMLHttpRequest != "undefined") {
            if (!ENVIRONMENT_IS_WORKER)
            throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";
            var lazyArray = new LazyUint8Array;
            Object.defineProperties(lazyArray, {
              length: {
                get: function() {
                  if (!this.lengthKnown) {
                    this.cacheLength()
                  }
                  return this._length
                }
              },
              chunkSize: {
                get: function() {
                  if (!this.lengthKnown) {
                    this.cacheLength()
                  }
                  return this._chunkSize
                }
              }
            });
            var properties = {
              isDevice: false,
              contents: lazyArray
            }
          } else {
            var properties = {
              isDevice: false,
              url: url
            }
          }
          var node = FS.createFile(parent, name, properties, canRead, canWrite);
          if (properties.contents) {
            node.contents = properties.contents
          } else if (properties.url) {
            node.contents = null;
            node.url = properties.url
          }
          Object.defineProperties(node, {
            usedBytes: {
              get: function() {
                return this.contents.length
              }
            }
          });
          var stream_ops = {};
          var keys = Object.keys(node.stream_ops);
          keys.forEach(key => {
            var fn = node.stream_ops[key];
            stream_ops[key] = function forceLoadLazyFile() {
              FS.forceLoadFile(node);
              return fn.apply(null, arguments)
            }
          });

          function writeChunks(stream, buffer, offset, length, position) {
            var contents = stream.node.contents;
            if (position >= contents.length) return 0;
            var size = Math.min(contents.length - position, length);
            if (contents.slice) {
              for (var i = 0; i < size; i++) {
                buffer[offset + i] = contents[position + i]
              }
            } else {
              for (var i = 0; i < size; i++) {
                buffer[offset + i] = contents.get(position + i)
              }
            }
            return size
          }
          stream_ops.read = (stream, buffer, offset, length, position) => {
            FS.forceLoadFile(node);
            return writeChunks(stream, buffer, offset, length, position)
          };
          stream_ops.mmap = (stream, length, position, prot, flags) => {
            FS.forceLoadFile(node);
            var ptr = mmapAlloc(length);
            if (!ptr) {
              throw new FS.ErrnoError(48)
            }
            writeChunks(stream, GROWABLE_HEAP_I8(), ptr, length, position);
            return {
              ptr: ptr,
              allocated: true
            }
          };
          node.stream_ops = stream_ops;
          return node
        }
      };
      var UTF8ToString = (ptr, maxBytesToRead) => {
        return ptr ? UTF8ArrayToString(GROWABLE_HEAP_U8(), ptr, maxBytesToRead) : ""
      };
      var SYSCALLS = {
        DEFAULT_POLLMASK: 5,
        calculateAt: function(dirfd, path, allowEmpty) {
          if (PATH.isAbs(path)) {
            return path
          }
          var dir;
          if (dirfd === -100) {
            dir = FS.cwd()
          } else {
            var dirstream = SYSCALLS.getStreamFromFD(dirfd);
            dir = dirstream.path
          }
          if (path.length == 0) {
            if (!allowEmpty) {
              throw new FS.ErrnoError(44)
            }
            return dir
          }
          return PATH.join2(dir, path)
        },
        doStat: function(func, path, buf) {
          try {
            var stat = func(path)
          } catch (e) {
            if (e && e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) {
              return -54
            }
            throw e
          }
          GROWABLE_HEAP_I32()[buf >> 2] = stat.dev;
          GROWABLE_HEAP_I32()[buf + 4 >> 2] = stat.mode;
          GROWABLE_HEAP_U32()[buf + 8 >> 2] = stat.nlink;
          GROWABLE_HEAP_I32()[buf + 12 >> 2] = stat.uid;
          GROWABLE_HEAP_I32()[buf + 16 >> 2] = stat.gid;
          GROWABLE_HEAP_I32()[buf + 20 >> 2] = stat.rdev;
          tempI64 = [stat.size >>> 0, (tempDouble = stat.size, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? +
              Math.floor(tempDouble / 4294967296) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>>
                0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[buf + 24 >> 2] = tempI64[0],
            GROWABLE_HEAP_I32()[buf + 28 >> 2] = tempI64[1];
          GROWABLE_HEAP_I32()[buf + 32 >> 2] = 4096;
          GROWABLE_HEAP_I32()[buf + 36 >> 2] = stat.blocks;
          var atime = stat.atime.getTime();
          var mtime = stat.mtime.getTime();
          var ctime = stat.ctime.getTime();
          tempI64 = [Math.floor(atime / 1e3) >>> 0, (tempDouble = Math.floor(atime / 1e3), +Math.abs(
              tempDouble) >= 1 ? tempDouble > 0 ? +Math.floor(tempDouble / 4294967296) >>> 0 : ~~+Math
            .ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[buf +
            40 >> 2] = tempI64[0], GROWABLE_HEAP_I32()[buf + 44 >> 2] = tempI64[1];
          GROWABLE_HEAP_U32()[buf + 48 >> 2] = atime % 1e3 * 1e3;
          tempI64 = [Math.floor(mtime / 1e3) >>> 0, (tempDouble = Math.floor(mtime / 1e3), +Math.abs(
              tempDouble) >= 1 ? tempDouble > 0 ? +Math.floor(tempDouble / 4294967296) >>> 0 : ~~+Math
            .ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[buf +
            56 >> 2] = tempI64[0], GROWABLE_HEAP_I32()[buf + 60 >> 2] = tempI64[1];
          GROWABLE_HEAP_U32()[buf + 64 >> 2] = mtime % 1e3 * 1e3;
          tempI64 = [Math.floor(ctime / 1e3) >>> 0, (tempDouble = Math.floor(ctime / 1e3), +Math.abs(
              tempDouble) >= 1 ? tempDouble > 0 ? +Math.floor(tempDouble / 4294967296) >>> 0 : ~~+Math
            .ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[buf +
            72 >> 2] = tempI64[0], GROWABLE_HEAP_I32()[buf + 76 >> 2] = tempI64[1];
          GROWABLE_HEAP_U32()[buf + 80 >> 2] = ctime % 1e3 * 1e3;
          tempI64 = [stat.ino >>> 0, (tempDouble = stat.ino, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? +
              Math.floor(tempDouble / 4294967296) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>>
                0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[buf + 88 >> 2] = tempI64[0],
            GROWABLE_HEAP_I32()[buf + 92 >> 2] = tempI64[1];
          return 0
        },
        doMsync: function(addr, stream, len, flags, offset) {
          if (!FS.isFile(stream.node.mode)) {
            throw new FS.ErrnoError(43)
          }
          if (flags & 2) {
            return 0
          }
          var buffer = GROWABLE_HEAP_U8().slice(addr, addr + len);
          FS.msync(stream, buffer, offset, len, flags)
        },
        varargs: undefined,
        get: function() {
          SYSCALLS.varargs += 4;
          var ret = GROWABLE_HEAP_I32()[SYSCALLS.varargs - 4 >> 2];
          return ret
        },
        getStr: function(ptr) {
          var ret = UTF8ToString(ptr);
          return ret
        },
        getStreamFromFD: function(fd) {
          var stream = FS.getStreamChecked(fd);
          return stream
        }
      };

      function _proc_exit(code) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(1, 1, code);
        EXITSTATUS = code;
        if (!keepRuntimeAlive()) {
          PThread.terminateAllThreads();
          if (Module["onExit"]) Module["onExit"](code);
          ABORT = true
        }
        quit_(code, new ExitStatus(code))
      }
      var exitJS = (status, implicit) => {
        EXITSTATUS = status;
        if (ENVIRONMENT_IS_PTHREAD) {
          exitOnMainThread(status);
          throw "unwind"
        }
        _proc_exit(status)
      };
      var _exit = exitJS;
      var handleException = e => {
        if (e instanceof ExitStatus || e == "unwind") {
          return EXITSTATUS
        }
        quit_(1, e)
      };
      var PThread = {
        unusedWorkers: [],
        runningWorkers: [],
        tlsInitFunctions: [],
        pthreads: {},
        init: function() {
          if (ENVIRONMENT_IS_PTHREAD) {
            PThread.initWorker()
          } else {
            PThread.initMainThread()
          }
        },
        initMainThread: function() {
          addOnPreRun(() => {
            addRunDependency("loading-workers");
            PThread.loadWasmModuleToAllWorkers(() => removeRunDependency("loading-workers"))
          })
        },
        initWorker: function() {
          noExitRuntime = false
        },
        setExitStatus: function(status) {
          EXITSTATUS = status
        },
        terminateAllThreads__deps: ["$terminateWorker"],
        terminateAllThreads: function() {
          for (var worker of PThread.runningWorkers) {
            terminateWorker(worker)
          }
          for (var worker of PThread.unusedWorkers) {
            terminateWorker(worker)
          }
          PThread.unusedWorkers = [];
          PThread.runningWorkers = [];
          PThread.pthreads = []
        },
        returnWorkerToPool: function(worker) {
          var pthread_ptr = worker.pthread_ptr;
          delete PThread.pthreads[pthread_ptr];
          PThread.unusedWorkers.push(worker);
          PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(worker), 1);
          worker.pthread_ptr = 0;
          __emscripten_thread_free_data(pthread_ptr)
        },
        receiveObjectTransfer: function(data) {
          if (typeof GL != "undefined") {
            Object.assign(GL.offscreenCanvases, data.offscreenCanvases);
            if (!Module["canvas"] && data.moduleCanvasId && GL.offscreenCanvases[data.moduleCanvasId]) {
              Module["canvas"] = GL.offscreenCanvases[data.moduleCanvasId].offscreenCanvas;
              Module["canvas"].id = data.moduleCanvasId
            }
          }
        },
        threadInitTLS: function() {
          PThread.tlsInitFunctions.forEach(f => f())
        },
        loadWasmModuleToWorker: worker => new Promise(onFinishedLoading => {
          worker.onmessage = e => {
            var d = e["data"];
            var cmd = d["cmd"];
            if (worker.pthread_ptr) PThread.currentProxiedOperationCallerThread = worker.pthread_ptr;
            if (d["targetThread"] && d["targetThread"] != _pthread_self()) {
              var targetWorker = PThread.pthreads[d.targetThread];
              if (targetWorker) {
                targetWorker.postMessage(d, d["transferList"])
              } else {
                err('Internal error! Worker sent a message "' + cmd + '" to target pthread ' + d[
                  "targetThread"] + ", but that thread no longer exists!")
              }
              PThread.currentProxiedOperationCallerThread = undefined;
              return
            }
            if (cmd === "checkMailbox") {
              checkMailbox()
            } else if (cmd === "spawnThread") {
              spawnThread(d)
            } else if (cmd === "cleanupThread") {
              cleanupThread(d["thread"])
            } else if (cmd === "killThread") {
              killThread(d["thread"])
            } else if (cmd === "cancelThread") {
              cancelThread(d["thread"])
            } else if (cmd === "loaded") {
              worker.loaded = true;
              onFinishedLoading(worker)
            } else if (cmd === "alert") {
              alert("Thread " + d["threadId"] + ": " + d["text"])
            } else if (d.target === "setimmediate") {
              worker.postMessage(d)
            } else if (cmd === "callHandler") {
              Module[d["handler"]](...d["args"])
            } else if (cmd) {
              err("worker sent an unknown command " + cmd)
            }
            PThread.currentProxiedOperationCallerThread = undefined
          };
          worker.onerror = e => {
            var message = "worker sent an error!";
            err(message + " " + e.filename + ":" + e.lineno + ": " + e.message);
            throw e
          };
          var handlers = [];
          var knownHandlers = ["onExit", "onAbort", "print", "printErr"];
          for (var handler of knownHandlers) {
            if (Module.hasOwnProperty(handler)) {
              handlers.push(handler)
            }
          }
          worker.postMessage({
            "cmd": "load",
            "handlers": handlers,
            "urlOrBlob": Module["mainScriptUrlOrBlob"] || _scriptDir,
            "wasmMemory": wasmMemory,
            "wasmModule": wasmModule
          })
        }),
        loadWasmModuleToAllWorkers: function(onMaybeReady) {
          onMaybeReady()
        },
        allocateUnusedWorker: function() {
          var worker;
          var pthreadMainJs = locateFile("Decoder.worker.js");
          worker = new Worker(pthreadMainJs);
          PThread.unusedWorkers.push(worker)
        },
        getNewWorker: function() {
          if (PThread.unusedWorkers.length == 0) {
            PThread.allocateUnusedWorker();
            PThread.loadWasmModuleToWorker(PThread.unusedWorkers[0])
          }
          return PThread.unusedWorkers.pop()
        }
      };
      Module["PThread"] = PThread;
      var callRuntimeCallbacks = callbacks => {
        while (callbacks.length > 0) {
          callbacks.shift()(Module)
        }
      };

      function establishStackSpace() {
        var pthread_ptr = _pthread_self();
        var stackHigh = GROWABLE_HEAP_I32()[pthread_ptr + 52 >> 2];
        var stackSize = GROWABLE_HEAP_I32()[pthread_ptr + 56 >> 2];
        var stackLow = stackHigh - stackSize;
        _emscripten_stack_set_limits(stackHigh, stackLow);
        stackRestore(stackHigh)
      }
      Module["establishStackSpace"] = establishStackSpace;

      function exitOnMainThread(returnCode) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(2, 0, returnCode);
        _exit(returnCode)
      }

      function getValue(ptr, type = "i8") {
        if (type.endsWith("*")) type = "*";
        switch (type) {
          case "i1":
            return GROWABLE_HEAP_I8()[ptr >> 0];
          case "i8":
            return GROWABLE_HEAP_I8()[ptr >> 0];
          case "i16":
            return GROWABLE_HEAP_I16()[ptr >> 1];
          case "i32":
            return GROWABLE_HEAP_I32()[ptr >> 2];
          case "i64":
            abort("to do getValue(i64) use WASM_BIGINT");
          case "float":
            return GROWABLE_HEAP_F32()[ptr >> 2];
          case "double":
            return GROWABLE_HEAP_F64()[ptr >> 3];
          case "*":
            return GROWABLE_HEAP_U32()[ptr >> 2];
          default:
            abort(`invalid type for getValue: ${type}`)
        }
      }
      var wasmTableMirror = [];
      var getWasmTableEntry = funcPtr => {
        var func = wasmTableMirror[funcPtr];
        if (!func) {
          if (funcPtr >= wasmTableMirror.length) wasmTableMirror.length = funcPtr + 1;
          wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr)
        }
        return func
      };

      function invokeEntryPoint(ptr, arg) {
        var result = getWasmTableEntry(ptr)(arg);
        if (keepRuntimeAlive()) {
          PThread.setExitStatus(result)
        } else {
          __emscripten_thread_exit(result)
        }
      }
      Module["invokeEntryPoint"] = invokeEntryPoint;

      function registerTLSInit(tlsInitFunc) {
        PThread.tlsInitFunctions.push(tlsInitFunc)
      }

      function setValue(ptr, value, type = "i8") {
        if (type.endsWith("*")) type = "*";
        switch (type) {
          case "i1":
            GROWABLE_HEAP_I8()[ptr >> 0] = value;
            break;
          case "i8":
            GROWABLE_HEAP_I8()[ptr >> 0] = value;
            break;
          case "i16":
            GROWABLE_HEAP_I16()[ptr >> 1] = value;
            break;
          case "i32":
            GROWABLE_HEAP_I32()[ptr >> 2] = value;
            break;
          case "i64":
            abort("to do setValue(i64) use WASM_BIGINT");
          case "float":
            GROWABLE_HEAP_F32()[ptr >> 2] = value;
            break;
          case "double":
            GROWABLE_HEAP_F64()[ptr >> 3] = value;
            break;
          case "*":
            GROWABLE_HEAP_U32()[ptr >> 2] = value;
            break;
          default:
            abort(`invalid type for setValue: ${type}`)
        }
      }

      function _AdditionDataCB(port, pstAddDataInfo, nUser) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(3, 0, port, pstAddDataInfo, nUser);
        JSPlayM4_AdditionDataCBFun(port, pstAddDataInfo, nUser)
      }

      function _DecCB(port, pYUVPCMData, size, type, timestamp, nUser) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(4, 0, port, pYUVPCMData, size, type, timestamp,
          nUser);
        var apYUVPCMData = new Uint8Array(size);
        apYUVPCMData.set(Module.HEAPU8.subarray(pYUVPCMData, pYUVPCMData + size));
        JSPlayM4_DecCallBack(port, apYUVPCMData, size, type, timestamp, nUser);
        apYUVPCMData = null
      }

      function _FirstFrameCB(port, nUser) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(5, 0, port, nUser);
        JSPlayM4_FirstFrameCallBack(port, nUser)
      }

      function _PrivateInfoCB(port, pstLinesInfo, pstFontInfo, pstImageInfo, nUser) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(6, 0, port, pstLinesInfo, pstFontInfo, pstImageInfo,
          nUser);
        JSPlayM4_PrivateInfoCallBack(port, pstLinesInfo, pstFontInfo, pstImageInfo, nUser)
      }

      function _RawDataCB(port, pRawData, size, rawVideoInfo, nUser) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(7, 0, port, pRawData, size, rawVideoInfo, nUser);
        var apData = new Uint8Array(size);
        apData.set(Module.HEAPU8.subarray(pRawData, pRawData + size));
        JSPlayM4_RawDataCallBack(port, apData, rawVideoInfo, nUser);
        apData = null
      }

      function _RunTimeInfoCB(port, pstRunTimeInfo, errorCode, nUser) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(8, 0, port, pstRunTimeInfo, errorCode, nUser);
        JSPlayM4_RunTimeInfoCallBack(port, pstRunTimeInfo, errorCode, nUser)
      }

      function _YUVDisplayCB(port, yuvData, size, timestamp, nUser) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(9, 0, port, yuvData, size, timestamp, nUser);
        var aYUVData = new Uint8Array(size);
        aYUVData.set(Module.HEAPU8.subarray(yuvData, yuvData + size));
        JSPlayM4_DisplayCallBack(port, aYUVData, size, timestamp, nUser);
        aYUVData = null
      }
      var ___assert_fail = (condition, filename, line, func) => {
        abort(`Assertion failed: ${UTF8ToString(condition)}, at: ` + [filename ? UTF8ToString(filename) :
          "unknown filename", line, func ? UTF8ToString(func) : "unknown function"
        ])
      };

      function ExceptionInfo(excPtr) {
        this.excPtr = excPtr;
        this.ptr = excPtr - 24;
        this.set_type = function(type) {
          GROWABLE_HEAP_U32()[this.ptr + 4 >> 2] = type
        };
        this.get_type = function() {
          return GROWABLE_HEAP_U32()[this.ptr + 4 >> 2]
        };
        this.set_destructor = function(destructor) {
          GROWABLE_HEAP_U32()[this.ptr + 8 >> 2] = destructor
        };
        this.get_destructor = function() {
          return GROWABLE_HEAP_U32()[this.ptr + 8 >> 2]
        };
        this.set_caught = function(caught) {
          caught = caught ? 1 : 0;
          GROWABLE_HEAP_I8()[this.ptr + 12 >> 0] = caught
        };
        this.get_caught = function() {
          return GROWABLE_HEAP_I8()[this.ptr + 12 >> 0] != 0
        };
        this.set_rethrown = function(rethrown) {
          rethrown = rethrown ? 1 : 0;
          GROWABLE_HEAP_I8()[this.ptr + 13 >> 0] = rethrown
        };
        this.get_rethrown = function() {
          return GROWABLE_HEAP_I8()[this.ptr + 13 >> 0] != 0
        };
        this.init = function(type, destructor) {
          this.set_adjusted_ptr(0);
          this.set_type(type);
          this.set_destructor(destructor)
        };
        this.set_adjusted_ptr = function(adjustedPtr) {
          GROWABLE_HEAP_U32()[this.ptr + 16 >> 2] = adjustedPtr
        };
        this.get_adjusted_ptr = function() {
          return GROWABLE_HEAP_U32()[this.ptr + 16 >> 2]
        };
        this.get_exception_ptr = function() {
          var isPointer = ___cxa_is_pointer_type(this.get_type());
          if (isPointer) {
            return GROWABLE_HEAP_U32()[this.excPtr >> 2]
          }
          var adjusted = this.get_adjusted_ptr();
          if (adjusted !== 0) return adjusted;
          return this.excPtr
        }
      }
      var exceptionLast = 0;
      var uncaughtExceptionCount = 0;

      function ___cxa_throw(ptr, type, destructor) {
        var info = new ExceptionInfo(ptr);
        info.init(type, destructor);
        exceptionLast = ptr;
        uncaughtExceptionCount++;
        throw exceptionLast
      }

      function ___emscripten_init_main_thread_js(tb) {
        __emscripten_thread_init(tb, !ENVIRONMENT_IS_WORKER, 1, !ENVIRONMENT_IS_WEB, 1048576);
        PThread.threadInitTLS()
      }

      function ___emscripten_thread_cleanup(thread) {
        if (!ENVIRONMENT_IS_PTHREAD) cleanupThread(thread);
        else postMessage({
          "cmd": "cleanupThread",
          "thread": thread
        })
      }

      function pthreadCreateProxied(pthread_ptr, attr, startRoutine, arg) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(10, 1, pthread_ptr, attr, startRoutine, arg);
        return ___pthread_create_js(pthread_ptr, attr, startRoutine, arg)
      }

      function ___pthread_create_js(pthread_ptr, attr, startRoutine, arg) {
        if (typeof SharedArrayBuffer == "undefined") {
          err("Current environment does not support SharedArrayBuffer, pthreads are not available!");
          return 6
        }
        var transferList = [];
        var error = 0;
        var transferredCanvasNames = attr ? GROWABLE_HEAP_U32()[attr + 40 >> 2] : 0;
        if (transferredCanvasNames == -1 >>> 0) transferredCanvasNames = "#canvas";
        else if (transferredCanvasNames) transferredCanvasNames = UTF8ToString(transferredCanvasNames).trim();
        if (transferredCanvasNames) transferredCanvasNames = transferredCanvasNames.split(",");
        var offscreenCanvases = {};
        var moduleCanvasId = Module["canvas"] ? Module["canvas"].id : "";
        for (var i = 0; i < transferredCanvasNames.length; i++) {
          var name = transferredCanvasNames[i].trim();
          var offscreenCanvasInfo;
          try {
            if (name == "#canvas") {
              if (!Module["canvas"]) {
                err('pthread_create: could not find canvas with ID "' + name + '" to transfer to thread!');
                error = 28;
                break
              }
              name = Module["canvas"].id
            }
            if (GL.offscreenCanvases[name]) {
              offscreenCanvasInfo = GL.offscreenCanvases[name];
              GL.offscreenCanvases[name] = null;
              if (Module["canvas"] instanceof OffscreenCanvas && name === Module["canvas"].id) Module["canvas"] =
                null
            } else if (!ENVIRONMENT_IS_PTHREAD) {
              var canvas = Module["canvas"] && Module["canvas"].id === name ? Module["canvas"] : document
                .querySelector(name);
              if (!canvas) {
                err('pthread_create: could not find canvas with ID "' + name + '" to transfer to thread!');
                error = 28;
                break
              }
              if (canvas.controlTransferredOffscreen) {
                err('pthread_create: cannot transfer canvas with ID "' + name +
                  '" to thread, since the current thread does not have control over it!');
                error = 63;
                break
              }
              if (canvas.transferControlToOffscreen) {
                if (!canvas.canvasSharedPtr) {
                  canvas.canvasSharedPtr = _malloc(12);
                  GROWABLE_HEAP_I32()[canvas.canvasSharedPtr >> 2] = canvas.width;
                  GROWABLE_HEAP_I32()[canvas.canvasSharedPtr + 4 >> 2] = canvas.height;
                  GROWABLE_HEAP_I32()[canvas.canvasSharedPtr + 8 >> 2] = 0
                }
                offscreenCanvasInfo = {
                  offscreenCanvas: canvas.transferControlToOffscreen(),
                  canvasSharedPtr: canvas.canvasSharedPtr,
                  id: canvas.id
                };
                canvas.controlTransferredOffscreen = true
              } else {
                err('pthread_create: cannot transfer control of canvas "' + name +
                  '" to pthread, because current browser does not support OffscreenCanvas!');
                err(
                  "pthread_create: Build with -sOFFSCREEN_FRAMEBUFFER to enable fallback proxying of GL commands from pthread to main thread.");
                return 52
              }
            }
            if (offscreenCanvasInfo) {
              transferList.push(offscreenCanvasInfo.offscreenCanvas);
              offscreenCanvases[offscreenCanvasInfo.id] = offscreenCanvasInfo
            }
          } catch (e) {
            err('pthread_create: failed to transfer control of canvas "' + name +
              '" to OffscreenCanvas! Error: ' + e);
            return 28
          }
        }
        if (ENVIRONMENT_IS_PTHREAD && (transferList.length === 0 || error)) {
          return pthreadCreateProxied(pthread_ptr, attr, startRoutine, arg)
        }
        if (error) return error;
        for (var canvas of Object.values(offscreenCanvases)) {
          GROWABLE_HEAP_I32()[canvas.canvasSharedPtr + 8 >> 2] = pthread_ptr
        }
        var threadParams = {
          startRoutine: startRoutine,
          pthread_ptr: pthread_ptr,
          arg: arg,
          moduleCanvasId: moduleCanvasId,
          offscreenCanvases: offscreenCanvases,
          transferList: transferList
        };
        if (ENVIRONMENT_IS_PTHREAD) {
          threadParams.cmd = "spawnThread";
          postMessage(threadParams, transferList);
          return 0
        }
        return spawnThread(threadParams)
      }
      var setErrNo = value => {
        GROWABLE_HEAP_I32()[___errno_location() >> 2] = value;
        return value
      };

      function ___syscall_fcntl64(fd, cmd, varargs) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(11, 1, fd, cmd, varargs);
        SYSCALLS.varargs = varargs;
        try {
          var stream = SYSCALLS.getStreamFromFD(fd);
          switch (cmd) {
            case 0: {
              var arg = SYSCALLS.get();
              if (arg < 0) {
                return -28
              }
              var newStream;
              newStream = FS.createStream(stream, arg);
              return newStream.fd
            }
            case 1:
            case 2:
              return 0;
            case 3:
              return stream.flags;
            case 4: {
              var arg = SYSCALLS.get();
              stream.flags |= arg;
              return 0
            }
            case 5: {
              var arg = SYSCALLS.get();
              var offset = 0;
              GROWABLE_HEAP_I16()[arg + offset >> 1] = 2;
              return 0
            }
            case 6:
            case 7:
              return 0;
            case 16:
            case 8:
              return -28;
            case 9:
              setErrNo(28);
              return -1;
            default: {
              return -28
            }
          }
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno
        }
      }

      function ___syscall_ioctl(fd, op, varargs) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(12, 1, fd, op, varargs);
        SYSCALLS.varargs = varargs;
        try {
          var stream = SYSCALLS.getStreamFromFD(fd);
          switch (op) {
            case 21509: {
              if (!stream.tty) return -59;
              return 0
            }
            case 21505: {
              if (!stream.tty) return -59;
              if (stream.tty.ops.ioctl_tcgets) {
                var termios = stream.tty.ops.ioctl_tcgets(stream);
                var argp = SYSCALLS.get();
                GROWABLE_HEAP_I32()[argp >> 2] = termios.c_iflag || 0;
                GROWABLE_HEAP_I32()[argp + 4 >> 2] = termios.c_oflag || 0;
                GROWABLE_HEAP_I32()[argp + 8 >> 2] = termios.c_cflag || 0;
                GROWABLE_HEAP_I32()[argp + 12 >> 2] = termios.c_lflag || 0;
                for (var i = 0; i < 32; i++) {
                  GROWABLE_HEAP_I8()[argp + i + 17 >> 0] = termios.c_cc[i] || 0
                }
                return 0
              }
              return 0
            }
            case 21510:
            case 21511:
            case 21512: {
              if (!stream.tty) return -59;
              return 0
            }
            case 21506:
            case 21507:
            case 21508: {
              if (!stream.tty) return -59;
              if (stream.tty.ops.ioctl_tcsets) {
                var argp = SYSCALLS.get();
                var c_iflag = GROWABLE_HEAP_I32()[argp >> 2];
                var c_oflag = GROWABLE_HEAP_I32()[argp + 4 >> 2];
                var c_cflag = GROWABLE_HEAP_I32()[argp + 8 >> 2];
                var c_lflag = GROWABLE_HEAP_I32()[argp + 12 >> 2];
                var c_cc = [];
                for (var i = 0; i < 32; i++) {
                  c_cc.push(GROWABLE_HEAP_I8()[argp + i + 17 >> 0])
                }
                return stream.tty.ops.ioctl_tcsets(stream.tty, op, {
                  c_iflag: c_iflag,
                  c_oflag: c_oflag,
                  c_cflag: c_cflag,
                  c_lflag: c_lflag,
                  c_cc: c_cc
                })
              }
              return 0
            }
            case 21519: {
              if (!stream.tty) return -59;
              var argp = SYSCALLS.get();
              GROWABLE_HEAP_I32()[argp >> 2] = 0;
              return 0
            }
            case 21520: {
              if (!stream.tty) return -59;
              return -28
            }
            case 21531: {
              var argp = SYSCALLS.get();
              return FS.ioctl(stream, op, argp)
            }
            case 21523: {
              if (!stream.tty) return -59;
              if (stream.tty.ops.ioctl_tiocgwinsz) {
                var winsize = stream.tty.ops.ioctl_tiocgwinsz(stream.tty);
                var argp = SYSCALLS.get();
                GROWABLE_HEAP_I16()[argp >> 1] = winsize[0];
                GROWABLE_HEAP_I16()[argp + 2 >> 1] = winsize[1]
              }
              return 0
            }
            case 21524: {
              if (!stream.tty) return -59;
              return 0
            }
            case 21515: {
              if (!stream.tty) return -59;
              return 0
            }
            default:
              return -28
          }
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno
        }
      }

      function ___syscall_openat(dirfd, path, flags, varargs) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(13, 1, dirfd, path, flags, varargs);
        SYSCALLS.varargs = varargs;
        try {
          path = SYSCALLS.getStr(path);
          path = SYSCALLS.calculateAt(dirfd, path);
          var mode = varargs ? SYSCALLS.get() : 0;
          return FS.open(path, flags, mode).fd
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno
        }
      }

      function __embind_register_bigint(primitiveType, name, size, minRange, maxRange) {}

      function getShiftFromSize(size) {
        switch (size) {
          case 1:
            return 0;
          case 2:
            return 1;
          case 4:
            return 2;
          case 8:
            return 3;
          default:
            throw new TypeError(`Unknown type size: ${size}`)
        }
      }

      function embind_init_charCodes() {
        var codes = new Array(256);
        for (var i = 0; i < 256; ++i) {
          codes[i] = String.fromCharCode(i)
        }
        embind_charCodes = codes
      }
      var embind_charCodes = undefined;

      function readLatin1String(ptr) {
        var ret = "";
        var c = ptr;
        while (GROWABLE_HEAP_U8()[c]) {
          ret += embind_charCodes[GROWABLE_HEAP_U8()[c++]]
        }
        return ret
      }
      var awaitingDependencies = {};
      var registeredTypes = {};
      var typeDependencies = {};
      var char_0 = 48;
      var char_9 = 57;

      function makeLegalFunctionName(name) {
        if (undefined === name) {
          return "_unknown"
        }
        name = name.replace(/[^a-zA-Z0-9_]/g, "$");
        var f = name.charCodeAt(0);
        if (f >= char_0 && f <= char_9) {
          return `_${name}`
        }
        return name
      }

      function createNamedFunction(name, body) {
        name = makeLegalFunctionName(name);
        return {
          [name]: function() {
            return body.apply(this, arguments)
          }
        } [name]
      }

      function extendError(baseErrorType, errorName) {
        var errorClass = createNamedFunction(errorName, function(message) {
          this.name = errorName;
          this.message = message;
          var stack = new Error(message).stack;
          if (stack !== undefined) {
            this.stack = this.toString() + "\n" + stack.replace(/^Error(:[^\n]*)?\n/, "")
          }
        });
        errorClass.prototype = Object.create(baseErrorType.prototype);
        errorClass.prototype.constructor = errorClass;
        errorClass.prototype.toString = function() {
          if (this.message === undefined) {
            return this.name
          } else {
            return `${this.name}: ${this.message}`
          }
        };
        return errorClass
      }
      var BindingError = undefined;

      function throwBindingError(message) {
        throw new BindingError(message)
      }
      var InternalError = undefined;

      function throwInternalError(message) {
        throw new InternalError(message)
      }

      function registerType(rawType, registeredInstance, options = {}) {
        if (!("argPackAdvance" in registeredInstance)) {
          throw new TypeError("registerType registeredInstance requires argPackAdvance")
        }
        var name = registeredInstance.name;
        if (!rawType) {
          throwBindingError(`type "${name}" must have a positive integer typeid pointer`)
        }
        if (registeredTypes.hasOwnProperty(rawType)) {
          if (options.ignoreDuplicateRegistrations) {
            return
          } else {
            throwBindingError(`Cannot register type '${name}' twice`)
          }
        }
        registeredTypes[rawType] = registeredInstance;
        delete typeDependencies[rawType];
        if (awaitingDependencies.hasOwnProperty(rawType)) {
          var callbacks = awaitingDependencies[rawType];
          delete awaitingDependencies[rawType];
          callbacks.forEach(cb => cb())
        }
      }

      function __embind_register_bool(rawType, name, size, trueValue, falseValue) {
        var shift = getShiftFromSize(size);
        name = readLatin1String(name);
        registerType(rawType, {
          name: name,
          "fromWireType": function(wt) {
            return !!wt
          },
          "toWireType": function(destructors, o) {
            return o ? trueValue : falseValue
          },
          "argPackAdvance": 8,
          "readValueFromPointer": function(pointer) {
            var heap;
            if (size === 1) {
              heap = GROWABLE_HEAP_I8()
            } else if (size === 2) {
              heap = GROWABLE_HEAP_I16()
            } else if (size === 4) {
              heap = GROWABLE_HEAP_I32()
            } else {
              throw new TypeError("Unknown boolean type size: " + name)
            }
            return this["fromWireType"](heap[pointer >> shift])
          },
          destructorFunction: null
        })
      }

      function HandleAllocator() {
        this.allocated = [undefined];
        this.freelist = [];
        this.get = function(id) {
          return this.allocated[id]
        };
        this.has = function(id) {
          return this.allocated[id] !== undefined
        };
        this.allocate = function(handle) {
          var id = this.freelist.pop() || this.allocated.length;
          this.allocated[id] = handle;
          return id
        };
        this.free = function(id) {
          this.allocated[id] = undefined;
          this.freelist.push(id)
        }
      }
      var emval_handles = new HandleAllocator;

      function __emval_decref(handle) {
        if (handle >= emval_handles.reserved && 0 === --emval_handles.get(handle).refcount) {
          emval_handles.free(handle)
        }
      }

      function count_emval_handles() {
        var count = 0;
        for (var i = emval_handles.reserved; i < emval_handles.allocated.length; ++i) {
          if (emval_handles.allocated[i] !== undefined) {
            ++count
          }
        }
        return count
      }

      function init_emval() {
        emval_handles.allocated.push({
          value: undefined
        }, {
          value: null
        }, {
          value: true
        }, {
          value: false
        });
        emval_handles.reserved = emval_handles.allocated.length;
        Module["count_emval_handles"] = count_emval_handles
      }
      var Emval = {
        toValue: handle => {
          if (!handle) {
            throwBindingError("Cannot use deleted val. handle = " + handle)
          }
          return emval_handles.get(handle).value
        },
        toHandle: value => {
          switch (value) {
            case undefined:
              return 1;
            case null:
              return 2;
            case true:
              return 3;
            case false:
              return 4;
            default: {
              return emval_handles.allocate({
                refcount: 1,
                value: value
              })
            }
          }
        }
      };

      function simpleReadValueFromPointer(pointer) {
        return this["fromWireType"](GROWABLE_HEAP_I32()[pointer >> 2])
      }

      function __embind_register_emval(rawType, name) {
        name = readLatin1String(name);
        registerType(rawType, {
          name: name,
          "fromWireType": function(handle) {
            var rv = Emval.toValue(handle);
            __emval_decref(handle);
            return rv
          },
          "toWireType": function(destructors, value) {
            return Emval.toHandle(value)
          },
          "argPackAdvance": 8,
          "readValueFromPointer": simpleReadValueFromPointer,
          destructorFunction: null
        })
      }

      function floatReadValueFromPointer(name, shift) {
        switch (shift) {
          case 2:
            return function(pointer) {
              return this["fromWireType"](GROWABLE_HEAP_F32()[pointer >> 2])
            };
          case 3:
            return function(pointer) {
              return this["fromWireType"](GROWABLE_HEAP_F64()[pointer >> 3])
            };
          default:
            throw new TypeError("Unknown float type: " + name)
        }
      }

      function __embind_register_float(rawType, name, size) {
        var shift = getShiftFromSize(size);
        name = readLatin1String(name);
        registerType(rawType, {
          name: name,
          "fromWireType": function(value) {
            return value
          },
          "toWireType": function(destructors, value) {
            return value
          },
          "argPackAdvance": 8,
          "readValueFromPointer": floatReadValueFromPointer(name, shift),
          destructorFunction: null
        })
      }

      function integerReadValueFromPointer(name, shift, signed) {
        switch (shift) {
          case 0:
            return signed ? function readS8FromPointer(pointer) {
              return GROWABLE_HEAP_I8()[pointer]
            } : function readU8FromPointer(pointer) {
              return GROWABLE_HEAP_U8()[pointer]
            };
          case 1:
            return signed ? function readS16FromPointer(pointer) {
              return GROWABLE_HEAP_I16()[pointer >> 1]
            } : function readU16FromPointer(pointer) {
              return GROWABLE_HEAP_U16()[pointer >> 1]
            };
          case 2:
            return signed ? function readS32FromPointer(pointer) {
              return GROWABLE_HEAP_I32()[pointer >> 2]
            } : function readU32FromPointer(pointer) {
              return GROWABLE_HEAP_U32()[pointer >> 2]
            };
          default:
            throw new TypeError("Unknown integer type: " + name)
        }
      }

      function __embind_register_integer(primitiveType, name, size, minRange, maxRange) {
        name = readLatin1String(name);
        if (maxRange === -1) {
          maxRange = 4294967295
        }
        var shift = getShiftFromSize(size);
        var fromWireType = value => value;
        if (minRange === 0) {
          var bitshift = 32 - 8 * size;
          fromWireType = value => value << bitshift >>> bitshift
        }
        var isUnsignedType = name.includes("unsigned");
        var checkAssertions = (value, toTypeName) => {};
        var toWireType;
        if (isUnsignedType) {
          toWireType = function(destructors, value) {
            checkAssertions(value, this.name);
            return value >>> 0
          }
        } else {
          toWireType = function(destructors, value) {
            checkAssertions(value, this.name);
            return value
          }
        }
        registerType(primitiveType, {
          name: name,
          "fromWireType": fromWireType,
          "toWireType": toWireType,
          "argPackAdvance": 8,
          "readValueFromPointer": integerReadValueFromPointer(name, shift, minRange !== 0),
          destructorFunction: null
        })
      }

      function __embind_register_memory_view(rawType, dataTypeIndex, name) {
        var typeMapping = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array,
          Float64Array
        ];
        var TA = typeMapping[dataTypeIndex];

        function decodeMemoryView(handle) {
          handle = handle >> 2;
          var heap = GROWABLE_HEAP_U32();
          var size = heap[handle];
          var data = heap[handle + 1];
          return new TA(heap.buffer, data, size)
        }
        name = readLatin1String(name);
        registerType(rawType, {
          name: name,
          "fromWireType": decodeMemoryView,
          "argPackAdvance": 8,
          "readValueFromPointer": decodeMemoryView
        }, {
          ignoreDuplicateRegistrations: true
        })
      }
      var stringToUTF8 = (str, outPtr, maxBytesToWrite) => {
        return stringToUTF8Array(str, GROWABLE_HEAP_U8(), outPtr, maxBytesToWrite)
      };

      function __embind_register_std_string(rawType, name) {
        name = readLatin1String(name);
        var stdStringIsUTF8 = name === "std::string";
        registerType(rawType, {
          name: name,
          "fromWireType": function(value) {
            var length = GROWABLE_HEAP_U32()[value >> 2];
            var payload = value + 4;
            var str;
            if (stdStringIsUTF8) {
              var decodeStartPtr = payload;
              for (var i = 0; i <= length; ++i) {
                var currentBytePtr = payload + i;
                if (i == length || GROWABLE_HEAP_U8()[currentBytePtr] == 0) {
                  var maxRead = currentBytePtr - decodeStartPtr;
                  var stringSegment = UTF8ToString(decodeStartPtr, maxRead);
                  if (str === undefined) {
                    str = stringSegment
                  } else {
                    str += String.fromCharCode(0);
                    str += stringSegment
                  }
                  decodeStartPtr = currentBytePtr + 1
                }
              }
            } else {
              var a = new Array(length);
              for (var i = 0; i < length; ++i) {
                a[i] = String.fromCharCode(GROWABLE_HEAP_U8()[payload + i])
              }
              str = a.join("")
            }
            _free(value);
            return str
          },
          "toWireType": function(destructors, value) {
            if (value instanceof ArrayBuffer) {
              value = new Uint8Array(value)
            }
            var length;
            var valueIsOfTypeString = typeof value == "string";
            if (!(valueIsOfTypeString || value instanceof Uint8Array ||
                value instanceof Uint8ClampedArray || value instanceof Int8Array)) {
              throwBindingError("Cannot pass non-string to std::string")
            }
            if (stdStringIsUTF8 && valueIsOfTypeString) {
              length = lengthBytesUTF8(value)
            } else {
              length = value.length
            }
            var base = _malloc(4 + length + 1);
            var ptr = base + 4;
            GROWABLE_HEAP_U32()[base >> 2] = length;
            if (stdStringIsUTF8 && valueIsOfTypeString) {
              stringToUTF8(value, ptr, length + 1)
            } else {
              if (valueIsOfTypeString) {
                for (var i = 0; i < length; ++i) {
                  var charCode = value.charCodeAt(i);
                  if (charCode > 255) {
                    _free(ptr);
                    throwBindingError("String has UTF-16 code units that do not fit in 8 bits")
                  }
                  GROWABLE_HEAP_U8()[ptr + i] = charCode
                }
              } else {
                for (var i = 0; i < length; ++i) {
                  GROWABLE_HEAP_U8()[ptr + i] = value[i]
                }
              }
            }
            if (destructors !== null) {
              destructors.push(_free, base)
            }
            return base
          },
          "argPackAdvance": 8,
          "readValueFromPointer": simpleReadValueFromPointer,
          destructorFunction: function(ptr) {
            _free(ptr)
          }
        })
      }
      var UTF16Decoder = typeof TextDecoder != "undefined" ? new TextDecoder("utf-16le") : undefined;
      var UTF16ToString = (ptr, maxBytesToRead) => {
        var endPtr = ptr;
        var idx = endPtr >> 1;
        var maxIdx = idx + maxBytesToRead / 2;
        while (!(idx >= maxIdx) && GROWABLE_HEAP_U16()[idx]) ++idx;
        endPtr = idx << 1;
        if (endPtr - ptr > 32 && UTF16Decoder) return UTF16Decoder.decode(GROWABLE_HEAP_U8().slice(ptr,
        endPtr));
        var str = "";
        for (var i = 0; !(i >= maxBytesToRead / 2); ++i) {
          var codeUnit = GROWABLE_HEAP_I16()[ptr + i * 2 >> 1];
          if (codeUnit == 0) break;
          str += String.fromCharCode(codeUnit)
        }
        return str
      };
      var stringToUTF16 = (str, outPtr, maxBytesToWrite) => {
        if (maxBytesToWrite === undefined) {
          maxBytesToWrite = 2147483647
        }
        if (maxBytesToWrite < 2) return 0;
        maxBytesToWrite -= 2;
        var startPtr = outPtr;
        var numCharsToWrite = maxBytesToWrite < str.length * 2 ? maxBytesToWrite / 2 : str.length;
        for (var i = 0; i < numCharsToWrite; ++i) {
          var codeUnit = str.charCodeAt(i);
          GROWABLE_HEAP_I16()[outPtr >> 1] = codeUnit;
          outPtr += 2
        }
        GROWABLE_HEAP_I16()[outPtr >> 1] = 0;
        return outPtr - startPtr
      };
      var lengthBytesUTF16 = str => {
        return str.length * 2
      };
      var UTF32ToString = (ptr, maxBytesToRead) => {
        var i = 0;
        var str = "";
        while (!(i >= maxBytesToRead / 4)) {
          var utf32 = GROWABLE_HEAP_I32()[ptr + i * 4 >> 2];
          if (utf32 == 0) break;
          ++i;
          if (utf32 >= 65536) {
            var ch = utf32 - 65536;
            str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023)
          } else {
            str += String.fromCharCode(utf32)
          }
        }
        return str
      };
      var stringToUTF32 = (str, outPtr, maxBytesToWrite) => {
        if (maxBytesToWrite === undefined) {
          maxBytesToWrite = 2147483647
        }
        if (maxBytesToWrite < 4) return 0;
        var startPtr = outPtr;
        var endPtr = startPtr + maxBytesToWrite - 4;
        for (var i = 0; i < str.length; ++i) {
          var codeUnit = str.charCodeAt(i);
          if (codeUnit >= 55296 && codeUnit <= 57343) {
            var trailSurrogate = str.charCodeAt(++i);
            codeUnit = 65536 + ((codeUnit & 1023) << 10) | trailSurrogate & 1023
          }
          GROWABLE_HEAP_I32()[outPtr >> 2] = codeUnit;
          outPtr += 4;
          if (outPtr + 4 > endPtr) break
        }
        GROWABLE_HEAP_I32()[outPtr >> 2] = 0;
        return outPtr - startPtr
      };
      var lengthBytesUTF32 = str => {
        var len = 0;
        for (var i = 0; i < str.length; ++i) {
          var codeUnit = str.charCodeAt(i);
          if (codeUnit >= 55296 && codeUnit <= 57343) ++i;
          len += 4
        }
        return len
      };
      var __embind_register_std_wstring = function(rawType, charSize, name) {
        name = readLatin1String(name);
        var decodeString, encodeString, getHeap, lengthBytesUTF, shift;
        if (charSize === 2) {
          decodeString = UTF16ToString;
          encodeString = stringToUTF16;
          lengthBytesUTF = lengthBytesUTF16;
          getHeap = () => GROWABLE_HEAP_U16();
          shift = 1
        } else if (charSize === 4) {
          decodeString = UTF32ToString;
          encodeString = stringToUTF32;
          lengthBytesUTF = lengthBytesUTF32;
          getHeap = () => GROWABLE_HEAP_U32();
          shift = 2
        }
        registerType(rawType, {
          name: name,
          "fromWireType": function(value) {
            var length = GROWABLE_HEAP_U32()[value >> 2];
            var HEAP = getHeap();
            var str;
            var decodeStartPtr = value + 4;
            for (var i = 0; i <= length; ++i) {
              var currentBytePtr = value + 4 + i * charSize;
              if (i == length || HEAP[currentBytePtr >> shift] == 0) {
                var maxReadBytes = currentBytePtr - decodeStartPtr;
                var stringSegment = decodeString(decodeStartPtr, maxReadBytes);
                if (str === undefined) {
                  str = stringSegment
                } else {
                  str += String.fromCharCode(0);
                  str += stringSegment
                }
                decodeStartPtr = currentBytePtr + charSize
              }
            }
            _free(value);
            return str
          },
          "toWireType": function(destructors, value) {
            if (!(typeof value == "string")) {
              throwBindingError(`Cannot pass non-string to C++ string type ${name}`)
            }
            var length = lengthBytesUTF(value);
            var ptr = _malloc(4 + length + charSize);
            GROWABLE_HEAP_U32()[ptr >> 2] = length >> shift;
            encodeString(value, ptr + 4, length + charSize);
            if (destructors !== null) {
              destructors.push(_free, ptr)
            }
            return ptr
          },
          "argPackAdvance": 8,
          "readValueFromPointer": simpleReadValueFromPointer,
          destructorFunction: function(ptr) {
            _free(ptr)
          }
        })
      };

      function __embind_register_void(rawType, name) {
        name = readLatin1String(name);
        registerType(rawType, {
          isVoid: true,
          name: name,
          "argPackAdvance": 0,
          "fromWireType": function() {
            return undefined
          },
          "toWireType": function(destructors, o) {
            return undefined
          }
        })
      }
      var __emscripten_fs_load_embedded_files = ptr => {
        do {
          var name_addr = GROWABLE_HEAP_U32()[ptr >> 2];
          ptr += 4;
          var len = GROWABLE_HEAP_U32()[ptr >> 2];
          ptr += 4;
          var content = GROWABLE_HEAP_U32()[ptr >> 2];
          ptr += 4;
          var name = UTF8ToString(name_addr);
          FS.createPath("/", PATH.dirname(name), true, true);
          FS.createDataFile(name, null, GROWABLE_HEAP_I8().subarray(content, content + len), true, true, true)
        } while (GROWABLE_HEAP_U32()[ptr >> 2])
      };
      var nowIsMonotonic = true;
      var __emscripten_get_now_is_monotonic = () => nowIsMonotonic;
      var maybeExit = () => {
        if (!keepRuntimeAlive()) {
          try {
            if (ENVIRONMENT_IS_PTHREAD) __emscripten_thread_exit(EXITSTATUS);
            else _exit(EXITSTATUS)
          } catch (e) {
            handleException(e)
          }
        }
      };
      var callUserCallback = func => {
        if (ABORT) {
          return
        }
        try {
          func();
          maybeExit()
        } catch (e) {
          handleException(e)
        }
      };

      function __emscripten_thread_mailbox_await(pthread_ptr) {
        if (typeof Atomics.waitAsync === "function") {
          var wait = Atomics.waitAsync(GROWABLE_HEAP_I32(), pthread_ptr >> 2, pthread_ptr);
          wait.value.then(checkMailbox);
          var waitingAsync = pthread_ptr + 128;
          Atomics.store(GROWABLE_HEAP_I32(), waitingAsync >> 2, 1)
        }
      }
      Module["__emscripten_thread_mailbox_await"] = __emscripten_thread_mailbox_await;
      var checkMailbox = function() {
        var pthread_ptr = _pthread_self();
        if (pthread_ptr) {
          __emscripten_thread_mailbox_await(pthread_ptr);
          callUserCallback(() => __emscripten_check_mailbox())
        }
      };
      Module["checkMailbox"] = checkMailbox;
      var __emscripten_notify_mailbox_postmessage = function(targetThreadId, currThreadId, mainThreadId) {
        if (targetThreadId == currThreadId) {
          setTimeout(() => checkMailbox())
        } else if (ENVIRONMENT_IS_PTHREAD) {
          postMessage({
            "targetThread": targetThreadId,
            "cmd": "checkMailbox"
          })
        } else {
          var worker = PThread.pthreads[targetThreadId];
          if (!worker) {
            return
          }
          worker.postMessage({
            "cmd": "checkMailbox"
          })
        }
      };
      var withStackSave = f => {
        var stack = stackSave();
        var ret = f();
        stackRestore(stack);
        return ret
      };
      var JSEvents = {
        inEventHandler: 0,
        removeAllEventListeners: function() {
          for (var i = JSEvents.eventHandlers.length - 1; i >= 0; --i) {
            JSEvents._removeHandler(i)
          }
          JSEvents.eventHandlers = [];
          JSEvents.deferredCalls = []
        },
        registerRemoveEventListeners: function() {
          if (!JSEvents.removeEventListenersRegistered) {
            __ATEXIT__.push(JSEvents.removeAllEventListeners);
            JSEvents.removeEventListenersRegistered = true
          }
        },
        deferredCalls: [],
        deferCall: function(targetFunction, precedence, argsList) {
          function arraysHaveEqualContent(arrA, arrB) {
            if (arrA.length != arrB.length) return false;
            for (var i in arrA) {
              if (arrA[i] != arrB[i]) return false
            }
            return true
          }
          for (var i in JSEvents.deferredCalls) {
            var call = JSEvents.deferredCalls[i];
            if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) {
              return
            }
          }
          JSEvents.deferredCalls.push({
            targetFunction: targetFunction,
            precedence: precedence,
            argsList: argsList
          });
          JSEvents.deferredCalls.sort(function(x, y) {
            return x.precedence < y.precedence
          })
        },
        removeDeferredCalls: function(targetFunction) {
          for (var i = 0; i < JSEvents.deferredCalls.length; ++i) {
            if (JSEvents.deferredCalls[i].targetFunction == targetFunction) {
              JSEvents.deferredCalls.splice(i, 1);
              --i
            }
          }
        },
        canPerformEventHandlerRequests: function() {
          return JSEvents.inEventHandler && JSEvents.currentEventHandler.allowsDeferredCalls
        },
        runDeferredCalls: function() {
          if (!JSEvents.canPerformEventHandlerRequests()) {
            return
          }
          for (var i = 0; i < JSEvents.deferredCalls.length; ++i) {
            var call = JSEvents.deferredCalls[i];
            JSEvents.deferredCalls.splice(i, 1);
            --i;
            call.targetFunction.apply(null, call.argsList)
          }
        },
        eventHandlers: [],
        removeAllHandlersOnTarget: function(target, eventTypeString) {
          for (var i = 0; i < JSEvents.eventHandlers.length; ++i) {
            if (JSEvents.eventHandlers[i].target == target && (!eventTypeString || eventTypeString == JSEvents
                .eventHandlers[i].eventTypeString)) {
              JSEvents._removeHandler(i--)
            }
          }
        },
        _removeHandler: function(i) {
          var h = JSEvents.eventHandlers[i];
          h.target.removeEventListener(h.eventTypeString, h.eventListenerFunc, h.useCapture);
          JSEvents.eventHandlers.splice(i, 1)
        },
        registerOrRemoveHandler: function(eventHandler) {
          if (!eventHandler.target) {
            return -4
          }
          var jsEventHandler = function jsEventHandler(event) {
            ++JSEvents.inEventHandler;
            JSEvents.currentEventHandler = eventHandler;
            JSEvents.runDeferredCalls();
            eventHandler.handlerFunc(event);
            JSEvents.runDeferredCalls();
            --JSEvents.inEventHandler
          };
          if (eventHandler.callbackfunc) {
            eventHandler.eventListenerFunc = jsEventHandler;
            eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, eventHandler
              .useCapture);
            JSEvents.eventHandlers.push(eventHandler);
            JSEvents.registerRemoveEventListeners()
          } else {
            for (var i = 0; i < JSEvents.eventHandlers.length; ++i) {
              if (JSEvents.eventHandlers[i].target == eventHandler.target && JSEvents.eventHandlers[i]
                .eventTypeString == eventHandler.eventTypeString) {
                JSEvents._removeHandler(i--)
              }
            }
          }
          return 0
        },
        queueEventHandlerOnThread_iiii: function(targetThread, eventHandlerFunc, eventTypeId, eventData,
          userData) {
          withStackSave(function() {
            var varargs = stackAlloc(12);
            GROWABLE_HEAP_I32()[varargs >> 2] = eventTypeId;
            GROWABLE_HEAP_I32()[varargs + 4 >> 2] = eventData;
            GROWABLE_HEAP_I32()[varargs + 8 >> 2] = userData;
            _emscripten_dispatch_to_thread_(targetThread, 637534208, eventHandlerFunc, eventData, varargs)
          })
        },
        getTargetThreadForEventCallback: function(targetThread) {
          switch (targetThread) {
            case 1:
              return 0;
            case 2:
              return PThread.currentProxiedOperationCallerThread;
            default:
              return targetThread
          }
        },
        getNodeNameForTarget: function(target) {
          if (!target) return "";
          if (target == window) return "#window";
          if (target == screen) return "#screen";
          return target && target.nodeName ? target.nodeName : ""
        },
        fullscreenEnabled: function() {
          return document.fullscreenEnabled || document.webkitFullscreenEnabled
        }
      };
      var stringToNewUTF8 = str => {
        var size = lengthBytesUTF8(str) + 1;
        var ret = _malloc(size);
        if (ret) stringToUTF8(str, ret, size);
        return ret
      };

      function setOffscreenCanvasSizeOnTargetThread(targetThread, targetCanvas, width, height) {
        targetCanvas = targetCanvas ? UTF8ToString(targetCanvas) : "";
        withStackSave(function() {
          var varargs = stackAlloc(12);
          var targetCanvasPtr = 0;
          if (targetCanvas) {
            targetCanvasPtr = stringToNewUTF8(targetCanvas)
          }
          GROWABLE_HEAP_I32()[varargs >> 2] = targetCanvasPtr;
          GROWABLE_HEAP_I32()[varargs + 4 >> 2] = width;
          GROWABLE_HEAP_I32()[varargs + 8 >> 2] = height;
          _emscripten_dispatch_to_thread_(targetThread, 654311424, 0, targetCanvasPtr, varargs)
        })
      }

      function webgl_enable_ANGLE_instanced_arrays(ctx) {
        var ext = ctx.getExtension("ANGLE_instanced_arrays");
        if (ext) {
          ctx["vertexAttribDivisor"] = function(index, divisor) {
            ext["vertexAttribDivisorANGLE"](index, divisor)
          };
          ctx["drawArraysInstanced"] = function(mode, first, count, primcount) {
            ext["drawArraysInstancedANGLE"](mode, first, count, primcount)
          };
          ctx["drawElementsInstanced"] = function(mode, count, type, indices, primcount) {
            ext["drawElementsInstancedANGLE"](mode, count, type, indices, primcount)
          };
          return 1
        }
      }

      function webgl_enable_OES_vertex_array_object(ctx) {
        var ext = ctx.getExtension("OES_vertex_array_object");
        if (ext) {
          ctx["createVertexArray"] = function() {
            return ext["createVertexArrayOES"]()
          };
          ctx["deleteVertexArray"] = function(vao) {
            ext["deleteVertexArrayOES"](vao)
          };
          ctx["bindVertexArray"] = function(vao) {
            ext["bindVertexArrayOES"](vao)
          };
          ctx["isVertexArray"] = function(vao) {
            return ext["isVertexArrayOES"](vao)
          };
          return 1
        }
      }

      function webgl_enable_WEBGL_draw_buffers(ctx) {
        var ext = ctx.getExtension("WEBGL_draw_buffers");
        if (ext) {
          ctx["drawBuffers"] = function(n, bufs) {
            ext["drawBuffersWEBGL"](n, bufs)
          };
          return 1
        }
      }

      function webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(ctx) {
        return !!(ctx.dibvbi = ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"))
      }

      function webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(ctx) {
        return !!(ctx.mdibvbi = ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance"))
      }

      function webgl_enable_WEBGL_multi_draw(ctx) {
        return !!(ctx.multiDrawWebgl = ctx.getExtension("WEBGL_multi_draw"))
      }
      var GL = {
        counter: 1,
        buffers: [],
        programs: [],
        framebuffers: [],
        renderbuffers: [],
        textures: [],
        shaders: [],
        vaos: [],
        contexts: {},
        offscreenCanvases: {},
        queries: [],
        samplers: [],
        transformFeedbacks: [],
        syncs: [],
        stringCache: {},
        stringiCache: {},
        unpackAlignment: 4,
        recordError: function recordError(errorCode) {
          if (!GL.lastError) {
            GL.lastError = errorCode
          }
        },
        getNewId: function(table) {
          var ret = GL.counter++;
          for (var i = table.length; i < ret; i++) {
            table[i] = null
          }
          return ret
        },
        getSource: function(shader, count, string, length) {
          var source = "";
          for (var i = 0; i < count; ++i) {
            var len = length ? GROWABLE_HEAP_I32()[length + i * 4 >> 2] : -1;
            source += UTF8ToString(GROWABLE_HEAP_I32()[string + i * 4 >> 2], len < 0 ? undefined : len)
          }
          return source
        },
        createContext: function(canvas, webGLContextAttributes) {
          if (Module["preinitializedWebGLContext"]) {
            var ctx = Module["preinitializedWebGLContext"];
            webGLContextAttributes.majorVersion = Number(ctx.getParameter(ctx.VERSION).match(
              /^WebGL (\d+).\d+/)[1])
          } else {
            if (!canvas.getContextSafariWebGL2Fixed) {
              canvas.getContextSafariWebGL2Fixed = canvas.getContext;

              function fixedGetContext(ver, attrs) {
                var gl = canvas.getContextSafariWebGL2Fixed(ver, attrs);
                return ver == "webgl" == gl instanceof WebGLRenderingContext ? gl : null
              }
              canvas.getContext = fixedGetContext
            }
            var ctx = webGLContextAttributes.majorVersion > 1 ? canvas.getContext("webgl2",
              webGLContextAttributes) : canvas.getContext("webgl", webGLContextAttributes)
          }
          if (!ctx) return 0;
          var handle = GL.registerContext(ctx, webGLContextAttributes);
          return handle
        },
        registerContext: function(ctx, webGLContextAttributes) {
          var handle = _malloc(8);
          GROWABLE_HEAP_I32()[handle + 4 >> 2] = _pthread_self();
          var context = {
            handle: handle,
            attributes: webGLContextAttributes,
            version: webGLContextAttributes.majorVersion,
            GLctx: ctx
          };
          if (ctx.canvas) ctx.canvas.GLctxObject = context;
          GL.contexts[handle] = context;
          if (typeof webGLContextAttributes.enableExtensionsByDefault == "undefined" || webGLContextAttributes
            .enableExtensionsByDefault) {
            GL.initExtensions(context)
          }
          return handle
        },
        makeContextCurrent: function(contextHandle) {
          GL.currentContext = GL.contexts[contextHandle];
          Module.ctx = GLctx = GL.currentContext && GL.currentContext.GLctx;
          return !(contextHandle && !GLctx)
        },
        getContext: function(contextHandle) {
          return GL.contexts[contextHandle]
        },
        deleteContext: function(contextHandle) {
          if (GL.currentContext === GL.contexts[contextHandle]) GL.currentContext = null;
          if (typeof JSEvents == "object") JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx
            .canvas);
          if (GL.contexts[contextHandle] && GL.contexts[contextHandle].GLctx.canvas) GL.contexts[
            contextHandle].GLctx.canvas.GLctxObject = undefined;
          _free(GL.contexts[contextHandle].handle);
          GL.contexts[contextHandle] = null
        },
        initExtensions: function(context) {
          if (!context) context = GL.currentContext;
          if (context.initExtensionsDone) return;
          context.initExtensionsDone = true;
          var GLctx = context.GLctx;
          webgl_enable_ANGLE_instanced_arrays(GLctx);
          webgl_enable_OES_vertex_array_object(GLctx);
          webgl_enable_WEBGL_draw_buffers(GLctx);
          webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);
          webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);
          if (context.version >= 2) {
            GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query_webgl2")
          }
          if (context.version < 2 || !GLctx.disjointTimerQueryExt) {
            GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query")
          }
          webgl_enable_WEBGL_multi_draw(GLctx);
          var exts = GLctx.getSupportedExtensions() || [];
          exts.forEach(function(ext) {
            if (!ext.includes("lose_context") && !ext.includes("debug")) {
              GLctx.getExtension(ext)
            }
          })
        }
      };

      function maybeCStringToJsString(cString) {
        return cString > 2 ? UTF8ToString(cString) : cString
      }

      function findCanvasEventTarget(target) {
        target = maybeCStringToJsString(target);
        return GL.offscreenCanvases[target.substr(1)] || target == "canvas" && Object.keys(GL.offscreenCanvases)[
          0] || typeof document != "undefined" && document.querySelector(target)
      }

      function setCanvasElementSizeCallingThread(target, width, height) {
        var canvas = findCanvasEventTarget(target);
        if (!canvas) return -4;
        if (canvas.canvasSharedPtr) {
          GROWABLE_HEAP_I32()[canvas.canvasSharedPtr >> 2] = width;
          GROWABLE_HEAP_I32()[canvas.canvasSharedPtr + 4 >> 2] = height
        }
        if (canvas.offscreenCanvas || !canvas.controlTransferredOffscreen) {
          if (canvas.offscreenCanvas) canvas = canvas.offscreenCanvas;
          var autoResizeViewport = false;
          if (canvas.GLctxObject && canvas.GLctxObject.GLctx) {
            var prevViewport = canvas.GLctxObject.GLctx.getParameter(2978);
            autoResizeViewport = prevViewport[0] === 0 && prevViewport[1] === 0 && prevViewport[2] === canvas
              .width && prevViewport[3] === canvas.height
          }
          canvas.width = width;
          canvas.height = height;
          if (autoResizeViewport) {
            canvas.GLctxObject.GLctx.viewport(0, 0, width, height)
          }
        } else if (canvas.canvasSharedPtr) {
          var targetThread = GROWABLE_HEAP_I32()[canvas.canvasSharedPtr + 8 >> 2];
          setOffscreenCanvasSizeOnTargetThread(targetThread, target, width, height);
          return 1
        } else {
          return -4
        }
        return 0
      }

      function setCanvasElementSizeMainThread(target, width, height) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(14, 1, target, width, height);
        return setCanvasElementSizeCallingThread(target, width, height)
      }

      function _emscripten_set_canvas_element_size(target, width, height) {
        var canvas = findCanvasEventTarget(target);
        if (canvas) {
          return setCanvasElementSizeCallingThread(target, width, height)
        }
        return setCanvasElementSizeMainThread(target, width, height)
      }
      var __emscripten_set_offscreencanvas_size = _emscripten_set_canvas_element_size;

      function __emscripten_thread_set_strongref(thread) {}
      var __emscripten_throw_longjmp = () => {
        throw Infinity
      };

      function readI53FromI64(ptr) {
        return GROWABLE_HEAP_U32()[ptr >> 2] + GROWABLE_HEAP_I32()[ptr + 4 >> 2] * 4294967296
      }
      var isLeapYear = year => {
        return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)
      };
      var MONTH_DAYS_LEAP_CUMULATIVE = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335];
      var MONTH_DAYS_REGULAR_CUMULATIVE = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
      var ydayFromDate = date => {
        var leap = isLeapYear(date.getFullYear());
        var monthDaysCumulative = leap ? MONTH_DAYS_LEAP_CUMULATIVE : MONTH_DAYS_REGULAR_CUMULATIVE;
        var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1;
        return yday
      };
      var __localtime_js = (time, tmPtr) => {
        var date = new Date(readI53FromI64(time) * 1e3);
        GROWABLE_HEAP_I32()[tmPtr >> 2] = date.getSeconds();
        GROWABLE_HEAP_I32()[tmPtr + 4 >> 2] = date.getMinutes();
        GROWABLE_HEAP_I32()[tmPtr + 8 >> 2] = date.getHours();
        GROWABLE_HEAP_I32()[tmPtr + 12 >> 2] = date.getDate();
        GROWABLE_HEAP_I32()[tmPtr + 16 >> 2] = date.getMonth();
        GROWABLE_HEAP_I32()[tmPtr + 20 >> 2] = date.getFullYear() - 1900;
        GROWABLE_HEAP_I32()[tmPtr + 24 >> 2] = date.getDay();
        var yday = ydayFromDate(date) | 0;
        GROWABLE_HEAP_I32()[tmPtr + 28 >> 2] = yday;
        GROWABLE_HEAP_I32()[tmPtr + 36 >> 2] = -(date.getTimezoneOffset() * 60);
        var start = new Date(date.getFullYear(), 0, 1);
        var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset();
        var winterOffset = start.getTimezoneOffset();
        var dst = (summerOffset != winterOffset && date.getTimezoneOffset() == Math.min(winterOffset,
          summerOffset)) | 0;
        GROWABLE_HEAP_I32()[tmPtr + 32 >> 2] = dst
      };
      var __tzset_js = (timezone, daylight, tzname) => {
        var currentYear = (new Date).getFullYear();
        var winter = new Date(currentYear, 0, 1);
        var summer = new Date(currentYear, 6, 1);
        var winterOffset = winter.getTimezoneOffset();
        var summerOffset = summer.getTimezoneOffset();
        var stdTimezoneOffset = Math.max(winterOffset, summerOffset);
        GROWABLE_HEAP_U32()[timezone >> 2] = stdTimezoneOffset * 60;
        GROWABLE_HEAP_I32()[daylight >> 2] = Number(winterOffset != summerOffset);

        function extractZone(date) {
          var match = date.toTimeString().match(/\(([A-Za-z ]+)\)$/);
          return match ? match[1] : "GMT"
        }
        var winterName = extractZone(winter);
        var summerName = extractZone(summer);
        var winterNamePtr = stringToNewUTF8(winterName);
        var summerNamePtr = stringToNewUTF8(summerName);
        if (summerOffset < winterOffset) {
          GROWABLE_HEAP_U32()[tzname >> 2] = winterNamePtr;
          GROWABLE_HEAP_U32()[tzname + 4 >> 2] = summerNamePtr
        } else {
          GROWABLE_HEAP_U32()[tzname >> 2] = summerNamePtr;
          GROWABLE_HEAP_U32()[tzname + 4 >> 2] = winterNamePtr
        }
      };
      var _abort = () => {
        abort("")
      };
      var runtimeKeepalivePush = () => {
        runtimeKeepaliveCounter += 1
      };

      function _emscripten_set_main_loop_timing(mode, value) {
        Browser.mainLoop.timingMode = mode;
        Browser.mainLoop.timingValue = value;
        if (!Browser.mainLoop.func) {
          return 1
        }
        if (!Browser.mainLoop.running) {
          runtimeKeepalivePush();
          Browser.mainLoop.running = true
        }
        if (mode == 0) {
          Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler_setTimeout() {
            var timeUntilNextTick = Math.max(0, Browser.mainLoop.tickStartTime + value -
            _emscripten_get_now()) | 0;
            setTimeout(Browser.mainLoop.runner, timeUntilNextTick)
          };
          Browser.mainLoop.method = "timeout"
        } else if (mode == 1) {
          Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler_rAF() {
            Browser.requestAnimationFrame(Browser.mainLoop.runner)
          };
          Browser.mainLoop.method = "rAF"
        } else if (mode == 2) {
          if (typeof setImmediate == "undefined") {
            var setImmediates = [];
            var emscriptenMainLoopMessageId = "setimmediate";
            var Browser_setImmediate_messageHandler = event => {
              if (event.data === emscriptenMainLoopMessageId || event.data.target ===
                emscriptenMainLoopMessageId) {
                event.stopPropagation();
                setImmediates.shift()()
              }
            };
            addEventListener("message", Browser_setImmediate_messageHandler, true);
            setImmediate = function Browser_emulated_setImmediate(func) {
              setImmediates.push(func);
              if (ENVIRONMENT_IS_WORKER) {
                if (Module["setImmediates"] === undefined) Module["setImmediates"] = [];
                Module["setImmediates"].push(func);
                postMessage({
                  target: emscriptenMainLoopMessageId
                })
              } else postMessage(emscriptenMainLoopMessageId, "*")
            }
          }
          Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler_setImmediate() {
            setImmediate(Browser.mainLoop.runner)
          };
          Browser.mainLoop.method = "immediate"
        }
        return 0
      }
      var _emscripten_get_now;
      _emscripten_get_now = () => performance.timeOrigin + performance.now();
      var runtimeKeepalivePop = () => {
        runtimeKeepaliveCounter -= 1
      };

      function setMainLoop(browserIterationFunc, fps, simulateInfiniteLoop, arg, noSetTiming) {
        assert(!Browser.mainLoop.func,
          "emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters."
          );
        Browser.mainLoop.func = browserIterationFunc;
        Browser.mainLoop.arg = arg;
        var thisMainLoopId = Browser.mainLoop.currentlyRunningMainloop;

        function checkIsRunning() {
          if (thisMainLoopId < Browser.mainLoop.currentlyRunningMainloop) {
            runtimeKeepalivePop();
            return false
          }
          return true
        }
        Browser.mainLoop.running = false;
        Browser.mainLoop.runner = function Browser_mainLoop_runner() {
          if (ABORT) return;
          if (Browser.mainLoop.queue.length > 0) {
            var start = Date.now();
            var blocker = Browser.mainLoop.queue.shift();
            blocker.func(blocker.arg);
            if (Browser.mainLoop.remainingBlockers) {
              var remaining = Browser.mainLoop.remainingBlockers;
              var next = remaining % 1 == 0 ? remaining - 1 : Math.floor(remaining);
              if (blocker.counted) {
                Browser.mainLoop.remainingBlockers = next
              } else {
                next = next + .5;
                Browser.mainLoop.remainingBlockers = (8 * remaining + next) / 9
              }
            }
            out('main loop blocker "' + blocker.name + '" took ' + (Date.now() - start) + " ms");
            Browser.mainLoop.updateStatus();
            if (!checkIsRunning()) return;
            setTimeout(Browser.mainLoop.runner, 0);
            return
          }
          if (!checkIsRunning()) return;
          Browser.mainLoop.currentFrameNumber = Browser.mainLoop.currentFrameNumber + 1 | 0;
          if (Browser.mainLoop.timingMode == 1 && Browser.mainLoop.timingValue > 1 && Browser.mainLoop
            .currentFrameNumber % Browser.mainLoop.timingValue != 0) {
            Browser.mainLoop.scheduler();
            return
          } else if (Browser.mainLoop.timingMode == 0) {
            Browser.mainLoop.tickStartTime = _emscripten_get_now()
          }
          if (typeof GL != "undefined" && GL.currentContext && !GL.currentContextIsProxied && !GL.currentContext
            .attributes.explicitSwapControl && GL.currentContext.GLctx.commit) {
            GL.currentContext.GLctx.commit()
          }
          Browser.mainLoop.runIter(browserIterationFunc);
          if (!checkIsRunning()) return;
          if (typeof SDL == "object" && SDL.audio && SDL.audio.queueNewAudioData) SDL.audio.queueNewAudioData();
          Browser.mainLoop.scheduler()
        };
        if (!noSetTiming) {
          if (fps && fps > 0) {
            _emscripten_set_main_loop_timing(0, 1e3 / fps)
          } else {
            _emscripten_set_main_loop_timing(1, 1)
          }
          Browser.mainLoop.scheduler()
        }
        if (simulateInfiniteLoop) {
          throw "unwind"
        }
      }
      var safeSetTimeout = (func, timeout) => {
        runtimeKeepalivePush();
        return setTimeout(() => {
          runtimeKeepalivePop();
          callUserCallback(func)
        }, timeout)
      };
      var warnOnce = text => {
        if (!warnOnce.shown) warnOnce.shown = {};
        if (!warnOnce.shown[text]) {
          warnOnce.shown[text] = 1;
          err(text)
        }
      };
      var Browser = {
        mainLoop: {
          running: false,
          scheduler: null,
          method: "",
          currentlyRunningMainloop: 0,
          func: null,
          arg: 0,
          timingMode: 0,
          timingValue: 0,
          currentFrameNumber: 0,
          queue: [],
          pause: function() {
            Browser.mainLoop.scheduler = null;
            Browser.mainLoop.currentlyRunningMainloop++
          },
          resume: function() {
            Browser.mainLoop.currentlyRunningMainloop++;
            var timingMode = Browser.mainLoop.timingMode;
            var timingValue = Browser.mainLoop.timingValue;
            var func = Browser.mainLoop.func;
            Browser.mainLoop.func = null;
            setMainLoop(func, 0, false, Browser.mainLoop.arg, true);
            _emscripten_set_main_loop_timing(timingMode, timingValue);
            Browser.mainLoop.scheduler()
          },
          updateStatus: function() {
            if (Module["setStatus"]) {
              var message = Module["statusMessage"] || "Please wait...";
              var remaining = Browser.mainLoop.remainingBlockers;
              var expected = Browser.mainLoop.expectedBlockers;
              if (remaining) {
                if (remaining < expected) {
                  Module["setStatus"](message + " (" + (expected - remaining) + "/" + expected + ")")
                } else {
                  Module["setStatus"](message)
                }
              } else {
                Module["setStatus"]("")
              }
            }
          },
          runIter: function(func) {
            if (ABORT) return;
            if (Module["preMainLoop"]) {
              var preRet = Module["preMainLoop"]();
              if (preRet === false) {
                return
              }
            }
            callUserCallback(func);
            if (Module["postMainLoop"]) Module["postMainLoop"]()
          }
        },
        isFullscreen: false,
        pointerLock: false,
        moduleContextCreatedCallbacks: [],
        workers: [],
        init: function() {
          if (Browser.initted) return;
          Browser.initted = true;
          var imagePlugin = {};
          imagePlugin["canHandle"] = function imagePlugin_canHandle(name) {
            return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name)
          };
          imagePlugin["handle"] = function imagePlugin_handle(byteArray, name, onload, onerror) {
            var b = new Blob([byteArray], {
              type: Browser.getMimetype(name)
            });
            if (b.size !== byteArray.length) {
              b = new Blob([new Uint8Array(byteArray).buffer], {
                type: Browser.getMimetype(name)
              })
            }
            var url = URL.createObjectURL(b);
            var img = new Image;
            img.onload = () => {
              assert(img.complete, "Image " + name + " could not be decoded");
              var canvas = document.createElement("canvas");
              canvas.width = img.width;
              canvas.height = img.height;
              var ctx = canvas.getContext("2d");
              ctx.drawImage(img, 0, 0);
              preloadedImages[name] = canvas;
              URL.revokeObjectURL(url);
              if (onload) onload(byteArray)
            };
            img.onerror = event => {
              out("Image " + url + " could not be decoded");
              if (onerror) onerror()
            };
            img.src = url
          };
          preloadPlugins.push(imagePlugin);
          var audioPlugin = {};
          audioPlugin["canHandle"] = function audioPlugin_canHandle(name) {
            return !Module.noAudioDecoding && name.substr(-4) in {
              ".ogg": 1,
              ".wav": 1,
              ".mp3": 1
            }
          };
          audioPlugin["handle"] = function audioPlugin_handle(byteArray, name, onload, onerror) {
            var done = false;

            function finish(audio) {
              if (done) return;
              done = true;
              preloadedAudios[name] = audio;
              if (onload) onload(byteArray)
            }
            var b = new Blob([byteArray], {
              type: Browser.getMimetype(name)
            });
            var url = URL.createObjectURL(b);
            var audio = new Audio;
            audio.addEventListener("canplaythrough", () => finish(audio), false);
            audio.onerror = function audio_onerror(event) {
              if (done) return;
              err("warning: browser could not fully decode audio " + name +
                ", trying slower base64 approach");

              function encode64(data) {
                var BASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
                var PAD = "=";
                var ret = "";
                var leftchar = 0;
                var leftbits = 0;
                for (var i = 0; i < data.length; i++) {
                  leftchar = leftchar << 8 | data[i];
                  leftbits += 8;
                  while (leftbits >= 6) {
                    var curr = leftchar >> leftbits - 6 & 63;
                    leftbits -= 6;
                    ret += BASE[curr]
                  }
                }
                if (leftbits == 2) {
                  ret += BASE[(leftchar & 3) << 4];
                  ret += PAD + PAD
                } else if (leftbits == 4) {
                  ret += BASE[(leftchar & 15) << 2];
                  ret += PAD
                }
                return ret
              }
              audio.src = "data:audio/x-" + name.substr(-3) + ";base64," + encode64(byteArray);
              finish(audio)
            };
            audio.src = url;
            safeSetTimeout(() => {
              finish(audio)
            }, 1e4)
          };
          preloadPlugins.push(audioPlugin);

          function pointerLockChange() {
            Browser.pointerLock = document["pointerLockElement"] === Module["canvas"] || document[
                "mozPointerLockElement"] === Module["canvas"] || document["webkitPointerLockElement"] ===
              Module["canvas"] || document["msPointerLockElement"] === Module["canvas"]
          }
          var canvas = Module["canvas"];
          if (canvas) {
            canvas.requestPointerLock = canvas["requestPointerLock"] || canvas["mozRequestPointerLock"] ||
              canvas["webkitRequestPointerLock"] || canvas["msRequestPointerLock"] || (() => {});
            canvas.exitPointerLock = document["exitPointerLock"] || document["mozExitPointerLock"] ||
              document["webkitExitPointerLock"] || document["msExitPointerLock"] || (() => {});
            canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
            document.addEventListener("pointerlockchange", pointerLockChange, false);
            document.addEventListener("mozpointerlockchange", pointerLockChange, false);
            document.addEventListener("webkitpointerlockchange", pointerLockChange, false);
            document.addEventListener("mspointerlockchange", pointerLockChange, false);
            if (Module["elementPointerLock"]) {
              canvas.addEventListener("click", ev => {
                if (!Browser.pointerLock && Module["canvas"].requestPointerLock) {
                  Module["canvas"].requestPointerLock();
                  ev.preventDefault()
                }
              }, false)
            }
          }
        },
        createContext: function(canvas, useWebGL, setInModule, webGLContextAttributes) {
          if (useWebGL && Module.ctx && canvas == Module.canvas) return Module.ctx;
          var ctx;
          var contextHandle;
          if (useWebGL) {
            var contextAttributes = {
              antialias: false,
              alpha: false,
              majorVersion: typeof WebGL2RenderingContext != "undefined" ? 2 : 1
            };
            if (webGLContextAttributes) {
              for (var attribute in webGLContextAttributes) {
                contextAttributes[attribute] = webGLContextAttributes[attribute]
              }
            }
            if (typeof GL != "undefined") {
              contextHandle = GL.createContext(canvas, contextAttributes);
              if (contextHandle) {
                ctx = GL.getContext(contextHandle).GLctx
              }
            }
          } else {
            ctx = canvas.getContext("2d")
          }
          if (!ctx) return null;
          if (setInModule) {
            if (!useWebGL) assert(typeof GLctx == "undefined",
              "cannot set in module if GLctx is used, but we are a non-GL context that would replace it");
            Module.ctx = ctx;
            if (useWebGL) GL.makeContextCurrent(contextHandle);
            Module.useWebGL = useWebGL;
            Browser.moduleContextCreatedCallbacks.forEach(callback => callback());
            Browser.init()
          }
          return ctx
        },
        destroyContext: function(canvas, useWebGL, setInModule) {},
        fullscreenHandlersInstalled: false,
        lockPointer: undefined,
        resizeCanvas: undefined,
        requestFullscreen: function(lockPointer, resizeCanvas) {
          Browser.lockPointer = lockPointer;
          Browser.resizeCanvas = resizeCanvas;
          if (typeof Browser.lockPointer == "undefined") Browser.lockPointer = true;
          if (typeof Browser.resizeCanvas == "undefined") Browser.resizeCanvas = false;
          var canvas = Module["canvas"];

          function fullscreenChange() {
            Browser.isFullscreen = false;
            var canvasContainer = canvas.parentNode;
            if ((document["fullscreenElement"] || document["mozFullScreenElement"] || document[
                "msFullscreenElement"] || document["webkitFullscreenElement"] || document[
                "webkitCurrentFullScreenElement"]) === canvasContainer) {
              canvas.exitFullscreen = Browser.exitFullscreen;
              if (Browser.lockPointer) canvas.requestPointerLock();
              Browser.isFullscreen = true;
              if (Browser.resizeCanvas) {
                Browser.setFullscreenCanvasSize()
              } else {
                Browser.updateCanvasDimensions(canvas)
              }
            } else {
              canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
              canvasContainer.parentNode.removeChild(canvasContainer);
              if (Browser.resizeCanvas) {
                Browser.setWindowedCanvasSize()
              } else {
                Browser.updateCanvasDimensions(canvas)
              }
            }
            if (Module["onFullScreen"]) Module["onFullScreen"](Browser.isFullscreen);
            if (Module["onFullscreen"]) Module["onFullscreen"](Browser.isFullscreen)
          }
          if (!Browser.fullscreenHandlersInstalled) {
            Browser.fullscreenHandlersInstalled = true;
            document.addEventListener("fullscreenchange", fullscreenChange, false);
            document.addEventListener("mozfullscreenchange", fullscreenChange, false);
            document.addEventListener("webkitfullscreenchange", fullscreenChange, false);
            document.addEventListener("MSFullscreenChange", fullscreenChange, false)
          }
          var canvasContainer = document.createElement("div");
          canvas.parentNode.insertBefore(canvasContainer, canvas);
          canvasContainer.appendChild(canvas);
          canvasContainer.requestFullscreen = canvasContainer["requestFullscreen"] || canvasContainer[
            "mozRequestFullScreen"] || canvasContainer["msRequestFullscreen"] || (canvasContainer[
            "webkitRequestFullscreen"] ? () => canvasContainer["webkitRequestFullscreen"](Element[
            "ALLOW_KEYBOARD_INPUT"]) : null) || (canvasContainer["webkitRequestFullScreen"] ? () =>
            canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]) : null);
          canvasContainer.requestFullscreen()
        },
        exitFullscreen: function() {
          if (!Browser.isFullscreen) {
            return false
          }
          var CFS = document["exitFullscreen"] || document["cancelFullScreen"] || document[
              "mozCancelFullScreen"] || document["msExitFullscreen"] || document["webkitCancelFullScreen"] ||
            (() => {});
          CFS.apply(document, []);
          return true
        },
        nextRAF: 0,
        fakeRequestAnimationFrame: function(func) {
          var now = Date.now();
          if (Browser.nextRAF === 0) {
            Browser.nextRAF = now + 1e3 / 60
          } else {
            while (now + 2 >= Browser.nextRAF) {
              Browser.nextRAF += 1e3 / 60
            }
          }
          var delay = Math.max(Browser.nextRAF - now, 0);
          setTimeout(func, delay)
        },
        requestAnimationFrame: function(func) {
          if (typeof requestAnimationFrame == "function") {
            requestAnimationFrame(func);
            return
          }
          var RAF = Browser.fakeRequestAnimationFrame;
          RAF(func)
        },
        safeSetTimeout: function(func, timeout) {
          return safeSetTimeout(func, timeout)
        },
        safeRequestAnimationFrame: function(func) {
          runtimeKeepalivePush();
          return Browser.requestAnimationFrame(() => {
            runtimeKeepalivePop();
            callUserCallback(func)
          })
        },
        getMimetype: function(name) {
          return {
            "jpg": "image/jpeg",
            "jpeg": "image/jpeg",
            "png": "image/png",
            "bmp": "image/bmp",
            "ogg": "audio/ogg",
            "wav": "audio/wav",
            "mp3": "audio/mpeg"
          } [name.substr(name.lastIndexOf(".") + 1)]
        },
        getUserMedia: function(func) {
          if (!window.getUserMedia) {
            window.getUserMedia = navigator["getUserMedia"] || navigator["mozGetUserMedia"]
          }
          window.getUserMedia(func)
        },
        getMovementX: function(event) {
          return event["movementX"] || event["mozMovementX"] || event["webkitMovementX"] || 0
        },
        getMovementY: function(event) {
          return event["movementY"] || event["mozMovementY"] || event["webkitMovementY"] || 0
        },
        getMouseWheelDelta: function(event) {
          var delta = 0;
          switch (event.type) {
            case "DOMMouseScroll":
              delta = event.detail / 3;
              break;
            case "mousewheel":
              delta = event.wheelDelta / 120;
              break;
            case "wheel":
              delta = event.deltaY;
              switch (event.deltaMode) {
                case 0:
                  delta /= 100;
                  break;
                case 1:
                  delta /= 3;
                  break;
                case 2:
                  delta *= 80;
                  break;
                default:
                  throw "unrecognized mouse wheel delta mode: " + event.deltaMode
              }
              break;
            default:
              throw "unrecognized mouse wheel event: " + event.type
          }
          return delta
        },
        mouseX: 0,
        mouseY: 0,
        mouseMovementX: 0,
        mouseMovementY: 0,
        touches: {},
        lastTouches: {},
        calculateMouseEvent: function(event) {
          if (Browser.pointerLock) {
            if (event.type != "mousemove" && "mozMovementX" in event) {
              Browser.mouseMovementX = Browser.mouseMovementY = 0
            } else {
              Browser.mouseMovementX = Browser.getMovementX(event);
              Browser.mouseMovementY = Browser.getMovementY(event)
            }
            if (typeof SDL != "undefined") {
              Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
              Browser.mouseY = SDL.mouseY + Browser.mouseMovementY
            } else {
              Browser.mouseX += Browser.mouseMovementX;
              Browser.mouseY += Browser.mouseMovementY
            }
          } else {
            var rect = Module["canvas"].getBoundingClientRect();
            var cw = Module["canvas"].width;
            var ch = Module["canvas"].height;
            var scrollX = typeof window.scrollX != "undefined" ? window.scrollX : window.pageXOffset;
            var scrollY = typeof window.scrollY != "undefined" ? window.scrollY : window.pageYOffset;
            if (event.type === "touchstart" || event.type === "touchend" || event.type === "touchmove") {
              var touch = event.touch;
              if (touch === undefined) {
                return
              }
              var adjustedX = touch.pageX - (scrollX + rect.left);
              var adjustedY = touch.pageY - (scrollY + rect.top);
              adjustedX = adjustedX * (cw / rect.width);
              adjustedY = adjustedY * (ch / rect.height);
              var coords = {
                x: adjustedX,
                y: adjustedY
              };
              if (event.type === "touchstart") {
                Browser.lastTouches[touch.identifier] = coords;
                Browser.touches[touch.identifier] = coords
              } else if (event.type === "touchend" || event.type === "touchmove") {
                var last = Browser.touches[touch.identifier];
                if (!last) last = coords;
                Browser.lastTouches[touch.identifier] = last;
                Browser.touches[touch.identifier] = coords
              }
              return
            }
            var x = event.pageX - (scrollX + rect.left);
            var y = event.pageY - (scrollY + rect.top);
            x = x * (cw / rect.width);
            y = y * (ch / rect.height);
            Browser.mouseMovementX = x - Browser.mouseX;
            Browser.mouseMovementY = y - Browser.mouseY;
            Browser.mouseX = x;
            Browser.mouseY = y
          }
        },
        resizeListeners: [],
        updateResizeListeners: function() {
          var canvas = Module["canvas"];
          Browser.resizeListeners.forEach(listener => listener(canvas.width, canvas.height))
        },
        setCanvasSize: function(width, height, noUpdates) {
          var canvas = Module["canvas"];
          Browser.updateCanvasDimensions(canvas, width, height);
          if (!noUpdates) Browser.updateResizeListeners()
        },
        windowedWidth: 0,
        windowedHeight: 0,
        setFullscreenCanvasSize: function() {
          if (typeof SDL != "undefined") {
            var flags = GROWABLE_HEAP_U32()[SDL.screen >> 2];
            flags = flags | 8388608;
            GROWABLE_HEAP_I32()[SDL.screen >> 2] = flags
          }
          Browser.updateCanvasDimensions(Module["canvas"]);
          Browser.updateResizeListeners()
        },
        setWindowedCanvasSize: function() {
          if (typeof SDL != "undefined") {
            var flags = GROWABLE_HEAP_U32()[SDL.screen >> 2];
            flags = flags & ~8388608;
            GROWABLE_HEAP_I32()[SDL.screen >> 2] = flags
          }
          Browser.updateCanvasDimensions(Module["canvas"]);
          Browser.updateResizeListeners()
        },
        updateCanvasDimensions: function(canvas, wNative, hNative) {
          if (wNative && hNative) {
            canvas.widthNative = wNative;
            canvas.heightNative = hNative
          } else {
            wNative = canvas.widthNative;
            hNative = canvas.heightNative
          }
          var w = wNative;
          var h = hNative;
          if (Module["forcedAspectRatio"] && Module["forcedAspectRatio"] > 0) {
            if (w / h < Module["forcedAspectRatio"]) {
              w = Math.round(h * Module["forcedAspectRatio"])
            } else {
              h = Math.round(w / Module["forcedAspectRatio"])
            }
          }
          if ((document["fullscreenElement"] || document["mozFullScreenElement"] || document[
              "msFullscreenElement"] || document["webkitFullscreenElement"] || document[
              "webkitCurrentFullScreenElement"]) === canvas.parentNode && typeof screen != "undefined") {
            var factor = Math.min(screen.width / w, screen.height / h);
            w = Math.round(w * factor);
            h = Math.round(h * factor)
          }
          if (Browser.resizeCanvas) {
            if (canvas.width != w) canvas.width = w;
            if (canvas.height != h) canvas.height = h;
            if (typeof canvas.style != "undefined") {
              canvas.style.removeProperty("width");
              canvas.style.removeProperty("height")
            }
          } else {
            if (canvas.width != wNative) canvas.width = wNative;
            if (canvas.height != hNative) canvas.height = hNative;
            if (typeof canvas.style != "undefined") {
              if (w != wNative || h != hNative) {
                canvas.style.setProperty("width", w + "px", "important");
                canvas.style.setProperty("height", h + "px", "important")
              } else {
                canvas.style.removeProperty("width");
                canvas.style.removeProperty("height")
              }
            }
          }
        }
      };
      var AL = {
        QUEUE_INTERVAL: 25,
        QUEUE_LOOKAHEAD: .1,
        DEVICE_NAME: "Emscripten OpenAL",
        CAPTURE_DEVICE_NAME: "Emscripten OpenAL capture",
        ALC_EXTENSIONS: {
          ALC_SOFT_pause_device: true,
          ALC_SOFT_HRTF: true
        },
        AL_EXTENSIONS: {
          AL_EXT_float32: true,
          AL_SOFT_loop_points: true,
          AL_SOFT_source_length: true,
          AL_EXT_source_distance_model: true,
          AL_SOFT_source_spatialize: true
        },
        _alcErr: 0,
        alcErr: 0,
        deviceRefCounts: {},
        alcStringCache: {},
        paused: false,
        stringCache: {},
        contexts: {},
        currentCtx: null,
        buffers: {
          0: {
            id: 0,
            refCount: 0,
            audioBuf: null,
            frequency: 0,
            bytesPerSample: 2,
            channels: 1,
            length: 0
          }
        },
        paramArray: [],
        _nextId: 1,
        newId: function() {
          return AL.freeIds.length > 0 ? AL.freeIds.pop() : AL._nextId++
        },
        freeIds: [],
        scheduleContextAudio: function(ctx) {
          if (Browser.mainLoop.timingMode === 1 && document["visibilityState"] != "visible") {
            return
          }
          for (var i in ctx.sources) {
            AL.scheduleSourceAudio(ctx.sources[i])
          }
        },
        scheduleSourceAudio: function(src, lookahead) {
          if (Browser.mainLoop.timingMode === 1 && document["visibilityState"] != "visible") {
            return
          }
          if (src.state !== 4114) {
            return
          }
          var currentTime = AL.updateSourceTime(src);
          var startTime = src.bufStartTime;
          var startOffset = src.bufOffset;
          var bufCursor = src.bufsProcessed;
          for (var i = 0; i < src.audioQueue.length; i++) {
            var audioSrc = src.audioQueue[i];
            startTime = audioSrc._startTime + audioSrc._duration;
            startOffset = 0;
            bufCursor += audioSrc._skipCount + 1
          }
          if (!lookahead) {
            lookahead = AL.QUEUE_LOOKAHEAD
          }
          var lookaheadTime = currentTime + lookahead;
          var skipCount = 0;
          while (startTime < lookaheadTime) {
            if (bufCursor >= src.bufQueue.length) {
              if (src.looping) {
                bufCursor %= src.bufQueue.length
              } else {
                break
              }
            }
            var buf = src.bufQueue[bufCursor % src.bufQueue.length];
            if (buf.length === 0) {
              skipCount++;
              if (skipCount === src.bufQueue.length) {
                break
              }
            } else {
              var audioSrc = src.context.audioCtx.createBufferSource();
              audioSrc.buffer = buf.audioBuf;
              audioSrc.playbackRate.value = src.playbackRate;
              if (buf.audioBuf._loopStart || buf.audioBuf._loopEnd) {
                audioSrc.loopStart = buf.audioBuf._loopStart;
                audioSrc.loopEnd = buf.audioBuf._loopEnd
              }
              var duration = 0;
              if (src.type === 4136 && src.looping) {
                duration = Number.POSITIVE_INFINITY;
                audioSrc.loop = true;
                if (buf.audioBuf._loopStart) {
                  audioSrc.loopStart = buf.audioBuf._loopStart
                }
                if (buf.audioBuf._loopEnd) {
                  audioSrc.loopEnd = buf.audioBuf._loopEnd
                }
              } else {
                duration = (buf.audioBuf.duration - startOffset) / src.playbackRate
              }
              audioSrc._startOffset = startOffset;
              audioSrc._duration = duration;
              audioSrc._skipCount = skipCount;
              skipCount = 0;
              audioSrc.connect(src.gain);
              if (typeof audioSrc.start != "undefined") {
                startTime = Math.max(startTime, src.context.audioCtx.currentTime);
                audioSrc.start(startTime, startOffset)
              } else if (typeof audioSrc.noteOn != "undefined") {
                startTime = Math.max(startTime, src.context.audioCtx.currentTime);
                audioSrc.noteOn(startTime)
              }
              audioSrc._startTime = startTime;
              src.audioQueue.push(audioSrc);
              startTime += duration
            }
            startOffset = 0;
            bufCursor++
          }
        },
        updateSourceTime: function(src) {
          var currentTime = src.context.audioCtx.currentTime;
          if (src.state !== 4114) {
            return currentTime
          }
          if (!isFinite(src.bufStartTime)) {
            src.bufStartTime = currentTime - src.bufOffset / src.playbackRate;
            src.bufOffset = 0
          }
          var nextStartTime = 0;
          while (src.audioQueue.length) {
            var audioSrc = src.audioQueue[0];
            src.bufsProcessed += audioSrc._skipCount;
            nextStartTime = audioSrc._startTime + audioSrc._duration;
            if (currentTime < nextStartTime) {
              break
            }
            src.audioQueue.shift();
            src.bufStartTime = nextStartTime;
            src.bufOffset = 0;
            src.bufsProcessed++
          }
          if (src.bufsProcessed >= src.bufQueue.length && !src.looping) {
            AL.setSourceState(src, 4116)
          } else if (src.type === 4136 && src.looping) {
            var buf = src.bufQueue[0];
            if (buf.length === 0) {
              src.bufOffset = 0
            } else {
              var delta = (currentTime - src.bufStartTime) * src.playbackRate;
              var loopStart = buf.audioBuf._loopStart || 0;
              var loopEnd = buf.audioBuf._loopEnd || buf.audioBuf.duration;
              if (loopEnd <= loopStart) {
                loopEnd = buf.audioBuf.duration
              }
              if (delta < loopEnd) {
                src.bufOffset = delta
              } else {
                src.bufOffset = loopStart + (delta - loopStart) % (loopEnd - loopStart)
              }
            }
          } else if (src.audioQueue[0]) {
            src.bufOffset = (currentTime - src.audioQueue[0]._startTime) * src.playbackRate
          } else {
            if (src.type !== 4136 && src.looping) {
              var srcDuration = AL.sourceDuration(src) / src.playbackRate;
              if (srcDuration > 0) {
                src.bufStartTime += Math.floor((currentTime - src.bufStartTime) / srcDuration) * srcDuration
              }
            }
            for (var i = 0; i < src.bufQueue.length; i++) {
              if (src.bufsProcessed >= src.bufQueue.length) {
                if (src.looping) {
                  src.bufsProcessed %= src.bufQueue.length
                } else {
                  AL.setSourceState(src, 4116);
                  break
                }
              }
              var buf = src.bufQueue[src.bufsProcessed];
              if (buf.length > 0) {
                nextStartTime = src.bufStartTime + buf.audioBuf.duration / src.playbackRate;
                if (currentTime < nextStartTime) {
                  src.bufOffset = (currentTime - src.bufStartTime) * src.playbackRate;
                  break
                }
                src.bufStartTime = nextStartTime
              }
              src.bufOffset = 0;
              src.bufsProcessed++
            }
          }
          return currentTime
        },
        cancelPendingSourceAudio: function(src) {
          AL.updateSourceTime(src);
          for (var i = 1; i < src.audioQueue.length; i++) {
            var audioSrc = src.audioQueue[i];
            audioSrc.stop()
          }
          if (src.audioQueue.length > 1) {
            src.audioQueue.length = 1
          }
        },
        stopSourceAudio: function(src) {
          for (var i = 0; i < src.audioQueue.length; i++) {
            src.audioQueue[i].stop()
          }
          src.audioQueue.length = 0
        },
        setSourceState: function(src, state) {
          if (state === 4114) {
            if (src.state === 4114 || src.state == 4116) {
              src.bufsProcessed = 0;
              src.bufOffset = 0
            } else {}
            AL.stopSourceAudio(src);
            src.state = 4114;
            src.bufStartTime = Number.NEGATIVE_INFINITY;
            AL.scheduleSourceAudio(src)
          } else if (state === 4115) {
            if (src.state === 4114) {
              AL.updateSourceTime(src);
              AL.stopSourceAudio(src);
              src.state = 4115
            }
          } else if (state === 4116) {
            if (src.state !== 4113) {
              src.state = 4116;
              src.bufsProcessed = src.bufQueue.length;
              src.bufStartTime = Number.NEGATIVE_INFINITY;
              src.bufOffset = 0;
              AL.stopSourceAudio(src)
            }
          } else if (state === 4113) {
            if (src.state !== 4113) {
              src.state = 4113;
              src.bufsProcessed = 0;
              src.bufStartTime = Number.NEGATIVE_INFINITY;
              src.bufOffset = 0;
              AL.stopSourceAudio(src)
            }
          }
        },
        initSourcePanner: function(src) {
          if (src.type === 4144) {
            return
          }
          var templateBuf = AL.buffers[0];
          for (var i = 0; i < src.bufQueue.length; i++) {
            if (src.bufQueue[i].id !== 0) {
              templateBuf = src.bufQueue[i];
              break
            }
          }
          if (src.spatialize === 1 || src.spatialize === 2 && templateBuf.channels === 1) {
            if (src.panner) {
              return
            }
            src.panner = src.context.audioCtx.createPanner();
            AL.updateSourceGlobal(src);
            AL.updateSourceSpace(src);
            src.panner.connect(src.context.gain);
            src.gain.disconnect();
            src.gain.connect(src.panner)
          } else {
            if (!src.panner) {
              return
            }
            src.panner.disconnect();
            src.gain.disconnect();
            src.gain.connect(src.context.gain);
            src.panner = null
          }
        },
        updateContextGlobal: function(ctx) {
          for (var i in ctx.sources) {
            AL.updateSourceGlobal(ctx.sources[i])
          }
        },
        updateSourceGlobal: function(src) {
          var panner = src.panner;
          if (!panner) {
            return
          }
          panner.refDistance = src.refDistance;
          panner.maxDistance = src.maxDistance;
          panner.rolloffFactor = src.rolloffFactor;
          panner.panningModel = src.context.hrtf ? "HRTF" : "equalpower";
          var distanceModel = src.context.sourceDistanceModel ? src.distanceModel : src.context.distanceModel;
          switch (distanceModel) {
            case 0:
              panner.distanceModel = "inverse";
              panner.refDistance = 340282e33;
              break;
            case 53249:
            case 53250:
              panner.distanceModel = "inverse";
              break;
            case 53251:
            case 53252:
              panner.distanceModel = "linear";
              break;
            case 53253:
            case 53254:
              panner.distanceModel = "exponential";
              break
          }
        },
        updateListenerSpace: function(ctx) {
          var listener = ctx.audioCtx.listener;
          if (listener.positionX) {
            listener.positionX.value = ctx.listener.position[0];
            listener.positionY.value = ctx.listener.position[1];
            listener.positionZ.value = ctx.listener.position[2]
          } else {
            listener.setPosition(ctx.listener.position[0], ctx.listener.position[1], ctx.listener.position[2])
          }
          if (listener.forwardX) {
            listener.forwardX.value = ctx.listener.direction[0];
            listener.forwardY.value = ctx.listener.direction[1];
            listener.forwardZ.value = ctx.listener.direction[2];
            listener.upX.value = ctx.listener.up[0];
            listener.upY.value = ctx.listener.up[1];
            listener.upZ.value = ctx.listener.up[2]
          } else {
            listener.setOrientation(ctx.listener.direction[0], ctx.listener.direction[1], ctx.listener
              .direction[2], ctx.listener.up[0], ctx.listener.up[1], ctx.listener.up[2])
          }
          for (var i in ctx.sources) {
            AL.updateSourceSpace(ctx.sources[i])
          }
        },
        updateSourceSpace: function(src) {
          if (!src.panner) {
            return
          }
          var panner = src.panner;
          var posX = src.position[0];
          var posY = src.position[1];
          var posZ = src.position[2];
          var dirX = src.direction[0];
          var dirY = src.direction[1];
          var dirZ = src.direction[2];
          var listener = src.context.listener;
          var lPosX = listener.position[0];
          var lPosY = listener.position[1];
          var lPosZ = listener.position[2];
          if (src.relative) {
            var lBackX = -listener.direction[0];
            var lBackY = -listener.direction[1];
            var lBackZ = -listener.direction[2];
            var lUpX = listener.up[0];
            var lUpY = listener.up[1];
            var lUpZ = listener.up[2];
            var inverseMagnitude = (x, y, z) => {
              var length = Math.sqrt(x * x + y * y + z * z);
              if (length < Number.EPSILON) {
                return 0
              }
              return 1 / length
            };
            var invMag = inverseMagnitude(lBackX, lBackY, lBackZ);
            lBackX *= invMag;
            lBackY *= invMag;
            lBackZ *= invMag;
            invMag = inverseMagnitude(lUpX, lUpY, lUpZ);
            lUpX *= invMag;
            lUpY *= invMag;
            lUpZ *= invMag;
            var lRightX = lUpY * lBackZ - lUpZ * lBackY;
            var lRightY = lUpZ * lBackX - lUpX * lBackZ;
            var lRightZ = lUpX * lBackY - lUpY * lBackX;
            invMag = inverseMagnitude(lRightX, lRightY, lRightZ);
            lRightX *= invMag;
            lRightY *= invMag;
            lRightZ *= invMag;
            lUpX = lBackY * lRightZ - lBackZ * lRightY;
            lUpY = lBackZ * lRightX - lBackX * lRightZ;
            lUpZ = lBackX * lRightY - lBackY * lRightX;
            var oldX = dirX;
            var oldY = dirY;
            var oldZ = dirZ;
            dirX = oldX * lRightX + oldY * lUpX + oldZ * lBackX;
            dirY = oldX * lRightY + oldY * lUpY + oldZ * lBackY;
            dirZ = oldX * lRightZ + oldY * lUpZ + oldZ * lBackZ;
            oldX = posX;
            oldY = posY;
            oldZ = posZ;
            posX = oldX * lRightX + oldY * lUpX + oldZ * lBackX;
            posY = oldX * lRightY + oldY * lUpY + oldZ * lBackY;
            posZ = oldX * lRightZ + oldY * lUpZ + oldZ * lBackZ;
            posX += lPosX;
            posY += lPosY;
            posZ += lPosZ
          }
          if (panner.positionX) {
            if (posX != panner.positionX.value) panner.positionX.value = posX;
            if (posY != panner.positionY.value) panner.positionY.value = posY;
            if (posZ != panner.positionZ.value) panner.positionZ.value = posZ
          } else {
            panner.setPosition(posX, posY, posZ)
          }
          if (panner.orientationX) {
            if (dirX != panner.orientationX.value) panner.orientationX.value = dirX;
            if (dirY != panner.orientationY.value) panner.orientationY.value = dirY;
            if (dirZ != panner.orientationZ.value) panner.orientationZ.value = dirZ
          } else {
            panner.setOrientation(dirX, dirY, dirZ)
          }
          var oldShift = src.dopplerShift;
          var velX = src.velocity[0];
          var velY = src.velocity[1];
          var velZ = src.velocity[2];
          var lVelX = listener.velocity[0];
          var lVelY = listener.velocity[1];
          var lVelZ = listener.velocity[2];
          if (posX === lPosX && posY === lPosY && posZ === lPosZ || velX === lVelX && velY === lVelY &&
            velZ === lVelZ) {
            src.dopplerShift = 1
          } else {
            var speedOfSound = src.context.speedOfSound;
            var dopplerFactor = src.context.dopplerFactor;
            var slX = lPosX - posX;
            var slY = lPosY - posY;
            var slZ = lPosZ - posZ;
            var magSl = Math.sqrt(slX * slX + slY * slY + slZ * slZ);
            var vls = (slX * lVelX + slY * lVelY + slZ * lVelZ) / magSl;
            var vss = (slX * velX + slY * velY + slZ * velZ) / magSl;
            vls = Math.min(vls, speedOfSound / dopplerFactor);
            vss = Math.min(vss, speedOfSound / dopplerFactor);
            src.dopplerShift = (speedOfSound - dopplerFactor * vls) / (speedOfSound - dopplerFactor * vss)
          }
          if (src.dopplerShift !== oldShift) {
            AL.updateSourceRate(src)
          }
        },
        updateSourceRate: function(src) {
          if (src.state === 4114) {
            AL.cancelPendingSourceAudio(src);
            var audioSrc = src.audioQueue[0];
            if (!audioSrc) {
              return
            }
            var duration;
            if (src.type === 4136 && src.looping) {
              duration = Number.POSITIVE_INFINITY
            } else {
              duration = (audioSrc.buffer.duration - audioSrc._startOffset) / src.playbackRate
            }
            audioSrc._duration = duration;
            audioSrc.playbackRate.value = src.playbackRate;
            AL.scheduleSourceAudio(src)
          }
        },
        sourceDuration: function(src) {
          var length = 0;
          for (var i = 0; i < src.bufQueue.length; i++) {
            var audioBuf = src.bufQueue[i].audioBuf;
            length += audioBuf ? audioBuf.duration : 0
          }
          return length
        },
        sourceTell: function(src) {
          AL.updateSourceTime(src);
          var offset = 0;
          for (var i = 0; i < src.bufsProcessed; i++) {
            if (src.bufQueue[i].audioBuf) {
              offset += src.bufQueue[i].audioBuf.duration
            }
          }
          offset += src.bufOffset;
          return offset
        },
        sourceSeek: function(src, offset) {
          var playing = src.state == 4114;
          if (playing) {
            AL.setSourceState(src, 4113)
          }
          if (src.bufQueue[src.bufsProcessed].audioBuf !== null) {
            src.bufsProcessed = 0;
            while (offset > src.bufQueue[src.bufsProcessed].audioBuf.duration) {
              offset -= src.bufQueue[src.bufsProcessed].audiobuf.duration;
              src.bufsProcessed++
            }
            src.bufOffset = offset
          }
          if (playing) {
            AL.setSourceState(src, 4114)
          }
        },
        getGlobalParam: function(funcname, param) {
          if (!AL.currentCtx) {
            return null
          }
          switch (param) {
            case 49152:
              return AL.currentCtx.dopplerFactor;
            case 49155:
              return AL.currentCtx.speedOfSound;
            case 53248:
              return AL.currentCtx.distanceModel;
            default:
              AL.currentCtx.err = 40962;
              return null
          }
        },
        setGlobalParam: function(funcname, param, value) {
          if (!AL.currentCtx) {
            return
          }
          switch (param) {
            case 49152:
              if (!Number.isFinite(value) || value < 0) {
                AL.currentCtx.err = 40963;
                return
              }
              AL.currentCtx.dopplerFactor = value;
              AL.updateListenerSpace(AL.currentCtx);
              break;
            case 49155:
              if (!Number.isFinite(value) || value <= 0) {
                AL.currentCtx.err = 40963;
                return
              }
              AL.currentCtx.speedOfSound = value;
              AL.updateListenerSpace(AL.currentCtx);
              break;
            case 53248:
              switch (value) {
                case 0:
                case 53249:
                case 53250:
                case 53251:
                case 53252:
                case 53253:
                case 53254:
                  AL.currentCtx.distanceModel = value;
                  AL.updateContextGlobal(AL.currentCtx);
                  break;
                default:
                  AL.currentCtx.err = 40963;
                  return
              }
              break;
            default:
              AL.currentCtx.err = 40962;
              return
          }
        },
        getListenerParam: function(funcname, param) {
          if (!AL.currentCtx) {
            return null
          }
          switch (param) {
            case 4100:
              return AL.currentCtx.listener.position;
            case 4102:
              return AL.currentCtx.listener.velocity;
            case 4111:
              return AL.currentCtx.listener.direction.concat(AL.currentCtx.listener.up);
            case 4106:
              return AL.currentCtx.gain.gain.value;
            default:
              AL.currentCtx.err = 40962;
              return null
          }
        },
        setListenerParam: function(funcname, param, value) {
          if (!AL.currentCtx) {
            return
          }
          if (value === null) {
            AL.currentCtx.err = 40962;
            return
          }
          var listener = AL.currentCtx.listener;
          switch (param) {
            case 4100:
              if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) {
                AL.currentCtx.err = 40963;
                return
              }
              listener.position[0] = value[0];
              listener.position[1] = value[1];
              listener.position[2] = value[2];
              AL.updateListenerSpace(AL.currentCtx);
              break;
            case 4102:
              if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) {
                AL.currentCtx.err = 40963;
                return
              }
              listener.velocity[0] = value[0];
              listener.velocity[1] = value[1];
              listener.velocity[2] = value[2];
              AL.updateListenerSpace(AL.currentCtx);
              break;
            case 4106:
              if (!Number.isFinite(value) || value < 0) {
                AL.currentCtx.err = 40963;
                return
              }
              AL.currentCtx.gain.gain.value = value;
              break;
            case 4111:
              if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2]) || !
                Number.isFinite(value[3]) || !Number.isFinite(value[4]) || !Number.isFinite(value[5])) {
                AL.currentCtx.err = 40963;
                return
              }
              listener.direction[0] = value[0];
              listener.direction[1] = value[1];
              listener.direction[2] = value[2];
              listener.up[0] = value[3];
              listener.up[1] = value[4];
              listener.up[2] = value[5];
              AL.updateListenerSpace(AL.currentCtx);
              break;
            default:
              AL.currentCtx.err = 40962;
              return
          }
        },
        getBufferParam: function(funcname, bufferId, param) {
          if (!AL.currentCtx) {
            return
          }
          var buf = AL.buffers[bufferId];
          if (!buf || bufferId === 0) {
            AL.currentCtx.err = 40961;
            return
          }
          switch (param) {
            case 8193:
              return buf.frequency;
            case 8194:
              return buf.bytesPerSample * 8;
            case 8195:
              return buf.channels;
            case 8196:
              return buf.length * buf.bytesPerSample * buf.channels;
            case 8213:
              if (buf.length === 0) {
                return [0, 0]
              }
              return [(buf.audioBuf._loopStart || 0) * buf.frequency, (buf.audioBuf._loopEnd || buf.length) *
                buf.frequency
              ];
            default:
              AL.currentCtx.err = 40962;
              return null
          }
        },
        setBufferParam: function(funcname, bufferId, param, value) {
          if (!AL.currentCtx) {
            return
          }
          var buf = AL.buffers[bufferId];
          if (!buf || bufferId === 0) {
            AL.currentCtx.err = 40961;
            return
          }
          if (value === null) {
            AL.currentCtx.err = 40962;
            return
          }
          switch (param) {
            case 8196:
              if (value !== 0) {
                AL.currentCtx.err = 40963;
                return
              }
              break;
            case 8213:
              if (value[0] < 0 || value[0] > buf.length || value[1] < 0 || value[1] > buf.Length || value[
                0] >= value[1]) {
                AL.currentCtx.err = 40963;
                return
              }
              if (buf.refCount > 0) {
                AL.currentCtx.err = 40964;
                return
              }
              if (buf.audioBuf) {
                buf.audioBuf._loopStart = value[0] / buf.frequency;
                buf.audioBuf._loopEnd = value[1] / buf.frequency
              }
              break;
            default:
              AL.currentCtx.err = 40962;
              return
          }
        },
        getSourceParam: function(funcname, sourceId, param) {
          if (!AL.currentCtx) {
            return null
          }
          var src = AL.currentCtx.sources[sourceId];
          if (!src) {
            AL.currentCtx.err = 40961;
            return null
          }
          switch (param) {
            case 514:
              return src.relative;
            case 4097:
              return src.coneInnerAngle;
            case 4098:
              return src.coneOuterAngle;
            case 4099:
              return src.pitch;
            case 4100:
              return src.position;
            case 4101:
              return src.direction;
            case 4102:
              return src.velocity;
            case 4103:
              return src.looping;
            case 4105:
              if (src.type === 4136) {
                return src.bufQueue[0].id
              }
              return 0;
            case 4106:
              return src.gain.gain.value;
            case 4109:
              return src.minGain;
            case 4110:
              return src.maxGain;
            case 4112:
              return src.state;
            case 4117:
              if (src.bufQueue.length === 1 && src.bufQueue[0].id === 0) {
                return 0
              }
              return src.bufQueue.length;
            case 4118:
              if (src.bufQueue.length === 1 && src.bufQueue[0].id === 0 || src.looping) {
                return 0
              }
              return src.bufsProcessed;
            case 4128:
              return src.refDistance;
            case 4129:
              return src.rolloffFactor;
            case 4130:
              return src.coneOuterGain;
            case 4131:
              return src.maxDistance;
            case 4132:
              return AL.sourceTell(src);
            case 4133:
              var offset = AL.sourceTell(src);
              if (offset > 0) {
                offset *= src.bufQueue[0].frequency
              }
              return offset;
            case 4134:
              var offset = AL.sourceTell(src);
              if (offset > 0) {
                offset *= src.bufQueue[0].frequency * src.bufQueue[0].bytesPerSample
              }
              return offset;
            case 4135:
              return src.type;
            case 4628:
              return src.spatialize;
            case 8201:
              var length = 0;
              var bytesPerFrame = 0;
              for (var i = 0; i < src.bufQueue.length; i++) {
                length += src.bufQueue[i].length;
                if (src.bufQueue[i].id !== 0) {
                  bytesPerFrame = src.bufQueue[i].bytesPerSample * src.bufQueue[i].channels
                }
              }
              return length * bytesPerFrame;
            case 8202:
              var length = 0;
              for (var i = 0; i < src.bufQueue.length; i++) {
                length += src.bufQueue[i].length
              }
              return length;
            case 8203:
              return AL.sourceDuration(src);
            case 53248:
              return src.distanceModel;
            default:
              AL.currentCtx.err = 40962;
              return null
          }
        },
        setSourceParam: function(funcname, sourceId, param, value) {
          if (!AL.currentCtx) {
            return
          }
          var src = AL.currentCtx.sources[sourceId];
          if (!src) {
            AL.currentCtx.err = 40961;
            return
          }
          if (value === null) {
            AL.currentCtx.err = 40962;
            return
          }
          switch (param) {
            case 514:
              if (value === 1) {
                src.relative = true;
                AL.updateSourceSpace(src)
              } else if (value === 0) {
                src.relative = false;
                AL.updateSourceSpace(src)
              } else {
                AL.currentCtx.err = 40963;
                return
              }
              break;
            case 4097:
              if (!Number.isFinite(value)) {
                AL.currentCtx.err = 40963;
                return
              }
              src.coneInnerAngle = value;
              if (src.panner) {
                src.panner.coneInnerAngle = value % 360
              }
              break;
            case 4098:
              if (!Number.isFinite(value)) {
                AL.currentCtx.err = 40963;
                return
              }
              src.coneOuterAngle = value;
              if (src.panner) {
                src.panner.coneOuterAngle = value % 360
              }
              break;
            case 4099:
              if (!Number.isFinite(value) || value <= 0) {
                AL.currentCtx.err = 40963;
                return
              }
              if (src.pitch === value) {
                break
              }
              src.pitch = value;
              AL.updateSourceRate(src);
              break;
            case 4100:
              if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) {
                AL.currentCtx.err = 40963;
                return
              }
              src.position[0] = value[0];
              src.position[1] = value[1];
              src.position[2] = value[2];
              AL.updateSourceSpace(src);
              break;
            case 4101:
              if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) {
                AL.currentCtx.err = 40963;
                return
              }
              src.direction[0] = value[0];
              src.direction[1] = value[1];
              src.direction[2] = value[2];
              AL.updateSourceSpace(src);
              break;
            case 4102:
              if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) {
                AL.currentCtx.err = 40963;
                return
              }
              src.velocity[0] = value[0];
              src.velocity[1] = value[1];
              src.velocity[2] = value[2];
              AL.updateSourceSpace(src);
              break;
            case 4103:
              if (value === 1) {
                src.looping = true;
                AL.updateSourceTime(src);
                if (src.type === 4136 && src.audioQueue.length > 0) {
                  var audioSrc = src.audioQueue[0];
                  audioSrc.loop = true;
                  audioSrc._duration = Number.POSITIVE_INFINITY
                }
              } else if (value === 0) {
                src.looping = false;
                var currentTime = AL.updateSourceTime(src);
                if (src.type === 4136 && src.audioQueue.length > 0) {
                  var audioSrc = src.audioQueue[0];
                  audioSrc.loop = false;
                  audioSrc._duration = src.bufQueue[0].audioBuf.duration / src.playbackRate;
                  audioSrc._startTime = currentTime - src.bufOffset / src.playbackRate
                }
              } else {
                AL.currentCtx.err = 40963;
                return
              }
              break;
            case 4105:
              if (src.state === 4114 || src.state === 4115) {
                AL.currentCtx.err = 40964;
                return
              }
              if (value === 0) {
                for (var i in src.bufQueue) {
                  src.bufQueue[i].refCount--
                }
                src.bufQueue.length = 1;
                src.bufQueue[0] = AL.buffers[0];
                src.bufsProcessed = 0;
                src.type = 4144
              } else {
                var buf = AL.buffers[value];
                if (!buf) {
                  AL.currentCtx.err = 40963;
                  return
                }
                for (var i in src.bufQueue) {
                  src.bufQueue[i].refCount--
                }
                src.bufQueue.length = 0;
                buf.refCount++;
                src.bufQueue = [buf];
                src.bufsProcessed = 0;
                src.type = 4136
              }
              AL.initSourcePanner(src);
              AL.scheduleSourceAudio(src);
              break;
            case 4106:
              if (!Number.isFinite(value) || value < 0) {
                AL.currentCtx.err = 40963;
                return
              }
              src.gain.gain.value = value;
              break;
            case 4109:
              if (!Number.isFinite(value) || value < 0 || value > Math.min(src.maxGain, 1)) {
                AL.currentCtx.err = 40963;
                return
              }
              src.minGain = value;
              break;
            case 4110:
              if (!Number.isFinite(value) || value < Math.max(0, src.minGain) || value > 1) {
                AL.currentCtx.err = 40963;
                return
              }
              src.maxGain = value;
              break;
            case 4128:
              if (!Number.isFinite(value) || value < 0) {
                AL.currentCtx.err = 40963;
                return
              }
              src.refDistance = value;
              if (src.panner) {
                src.panner.refDistance = value
              }
              break;
            case 4129:
              if (!Number.isFinite(value) || value < 0) {
                AL.currentCtx.err = 40963;
                return
              }
              src.rolloffFactor = value;
              if (src.panner) {
                src.panner.rolloffFactor = value
              }
              break;
            case 4130:
              if (!Number.isFinite(value) || value < 0 || value > 1) {
                AL.currentCtx.err = 40963;
                return
              }
              src.coneOuterGain = value;
              if (src.panner) {
                src.panner.coneOuterGain = value
              }
              break;
            case 4131:
              if (!Number.isFinite(value) || value < 0) {
                AL.currentCtx.err = 40963;
                return
              }
              src.maxDistance = value;
              if (src.panner) {
                src.panner.maxDistance = value
              }
              break;
            case 4132:
              if (value < 0 || value > AL.sourceDuration(src)) {
                AL.currentCtx.err = 40963;
                return
              }
              AL.sourceSeek(src, value);
              break;
            case 4133:
              var srcLen = AL.sourceDuration(src);
              if (srcLen > 0) {
                var frequency;
                for (var bufId in src.bufQueue) {
                  if (bufId) {
                    frequency = src.bufQueue[bufId].frequency;
                    break
                  }
                }
                value /= frequency
              }
              if (value < 0 || value > srcLen) {
                AL.currentCtx.err = 40963;
                return
              }
              AL.sourceSeek(src, value);
              break;
            case 4134:
              var srcLen = AL.sourceDuration(src);
              if (srcLen > 0) {
                var bytesPerSec;
                for (var bufId in src.bufQueue) {
                  if (bufId) {
                    var buf = src.bufQueue[bufId];
                    bytesPerSec = buf.frequency * buf.bytesPerSample * buf.channels;
                    break
                  }
                }
                value /= bytesPerSec
              }
              if (value < 0 || value > srcLen) {
                AL.currentCtx.err = 40963;
                return
              }
              AL.sourceSeek(src, value);
              break;
            case 4628:
              if (value !== 0 && value !== 1 && value !== 2) {
                AL.currentCtx.err = 40963;
                return
              }
              src.spatialize = value;
              AL.initSourcePanner(src);
              break;
            case 8201:
            case 8202:
            case 8203:
              AL.currentCtx.err = 40964;
              break;
            case 53248:
              switch (value) {
                case 0:
                case 53249:
                case 53250:
                case 53251:
                case 53252:
                case 53253:
                case 53254:
                  src.distanceModel = value;
                  if (AL.currentCtx.sourceDistanceModel) {
                    AL.updateContextGlobal(AL.currentCtx)
                  }
                  break;
                default:
                  AL.currentCtx.err = 40963;
                  return
              }
              break;
            default:
              AL.currentCtx.err = 40962;
              return
          }
        },
        captures: {},
        sharedCaptureAudioCtx: null,
        requireValidCaptureDevice: function(deviceId, funcname) {
          if (deviceId === 0) {
            AL.alcErr = 40961;
            return null
          }
          var c = AL.captures[deviceId];
          if (!c) {
            AL.alcErr = 40961;
            return null
          }
          var err = c.mediaStreamError;
          if (err) {
            AL.alcErr = 40961;
            return null
          }
          return c
        }
      };

      function _alBufferData(bufferId, format, pData, size, freq) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(15, 1, bufferId, format, pData, size, freq);
        if (!AL.currentCtx) {
          return
        }
        var buf = AL.buffers[bufferId];
        if (!buf) {
          AL.currentCtx.err = 40963;
          return
        }
        if (freq <= 0) {
          AL.currentCtx.err = 40963;
          return
        }
        var audioBuf = null;
        try {
          switch (format) {
            case 4352:
              if (size > 0) {
                audioBuf = AL.currentCtx.audioCtx.createBuffer(1, size, freq);
                var channel0 = audioBuf.getChannelData(0);
                for (var i = 0; i < size; ++i) {
                  channel0[i] = GROWABLE_HEAP_U8()[pData++] * .0078125 - 1
                }
              }
              buf.bytesPerSample = 1;
              buf.channels = 1;
              buf.length = size;
              break;
            case 4353:
              if (size > 0) {
                audioBuf = AL.currentCtx.audioCtx.createBuffer(1, size >> 1, freq);
                var channel0 = audioBuf.getChannelData(0);
                pData >>= 1;
                for (var i = 0; i < size >> 1; ++i) {
                  channel0[i] = GROWABLE_HEAP_I16()[pData++] * 30517578125e-15
                }
              }
              buf.bytesPerSample = 2;
              buf.channels = 1;
              buf.length = size >> 1;
              break;
            case 4354:
              if (size > 0) {
                audioBuf = AL.currentCtx.audioCtx.createBuffer(2, size >> 1, freq);
                var channel0 = audioBuf.getChannelData(0);
                var channel1 = audioBuf.getChannelData(1);
                for (var i = 0; i < size >> 1; ++i) {
                  channel0[i] = GROWABLE_HEAP_U8()[pData++] * .0078125 - 1;
                  channel1[i] = GROWABLE_HEAP_U8()[pData++] * .0078125 - 1
                }
              }
              buf.bytesPerSample = 1;
              buf.channels = 2;
              buf.length = size >> 1;
              break;
            case 4355:
              if (size > 0) {
                audioBuf = AL.currentCtx.audioCtx.createBuffer(2, size >> 2, freq);
                var channel0 = audioBuf.getChannelData(0);
                var channel1 = audioBuf.getChannelData(1);
                pData >>= 1;
                for (var i = 0; i < size >> 2; ++i) {
                  channel0[i] = GROWABLE_HEAP_I16()[pData++] * 30517578125e-15;
                  channel1[i] = GROWABLE_HEAP_I16()[pData++] * 30517578125e-15
                }
              }
              buf.bytesPerSample = 2;
              buf.channels = 2;
              buf.length = size >> 2;
              break;
            case 65552:
              if (size > 0) {
                audioBuf = AL.currentCtx.audioCtx.createBuffer(1, size >> 2, freq);
                var channel0 = audioBuf.getChannelData(0);
                pData >>= 2;
                for (var i = 0; i < size >> 2; ++i) {
                  channel0[i] = GROWABLE_HEAP_F32()[pData++]
                }
              }
              buf.bytesPerSample = 4;
              buf.channels = 1;
              buf.length = size >> 2;
              break;
            case 65553:
              if (size > 0) {
                audioBuf = AL.currentCtx.audioCtx.createBuffer(2, size >> 3, freq);
                var channel0 = audioBuf.getChannelData(0);
                var channel1 = audioBuf.getChannelData(1);
                pData >>= 2;
                for (var i = 0; i < size >> 3; ++i) {
                  channel0[i] = GROWABLE_HEAP_F32()[pData++];
                  channel1[i] = GROWABLE_HEAP_F32()[pData++]
                }
              }
              buf.bytesPerSample = 4;
              buf.channels = 2;
              buf.length = size >> 3;
              break;
            default:
              AL.currentCtx.err = 40963;
              return
          }
          buf.frequency = freq;
          buf.audioBuf = audioBuf
        } catch (e) {
          AL.currentCtx.err = 40963;
          return
        }
      }

      function _alDeleteBuffers(count, pBufferIds) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(16, 1, count, pBufferIds);
        if (!AL.currentCtx) {
          return
        }
        for (var i = 0; i < count; ++i) {
          var bufId = GROWABLE_HEAP_I32()[pBufferIds + i * 4 >> 2];
          if (bufId === 0) {
            continue
          }
          if (!AL.buffers[bufId]) {
            AL.currentCtx.err = 40961;
            return
          }
          if (AL.buffers[bufId].refCount) {
            AL.currentCtx.err = 40964;
            return
          }
        }
        for (var i = 0; i < count; ++i) {
          var bufId = GROWABLE_HEAP_I32()[pBufferIds + i * 4 >> 2];
          if (bufId === 0) {
            continue
          }
          AL.deviceRefCounts[AL.buffers[bufId].deviceId]--;
          delete AL.buffers[bufId];
          AL.freeIds.push(bufId)
        }
      }

      function _alSourcei(sourceId, param, value) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(18, 1, sourceId, param, value);
        switch (param) {
          case 514:
          case 4097:
          case 4098:
          case 4103:
          case 4105:
          case 4128:
          case 4129:
          case 4131:
          case 4132:
          case 4133:
          case 4134:
          case 4628:
          case 8201:
          case 8202:
          case 53248:
            AL.setSourceParam("alSourcei", sourceId, param, value);
            break;
          default:
            AL.setSourceParam("alSourcei", sourceId, param, null);
            break
        }
      }

      function _alDeleteSources(count, pSourceIds) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(17, 1, count, pSourceIds);
        if (!AL.currentCtx) {
          return
        }
        for (var i = 0; i < count; ++i) {
          var srcId = GROWABLE_HEAP_I32()[pSourceIds + i * 4 >> 2];
          if (!AL.currentCtx.sources[srcId]) {
            AL.currentCtx.err = 40961;
            return
          }
        }
        for (var i = 0; i < count; ++i) {
          var srcId = GROWABLE_HEAP_I32()[pSourceIds + i * 4 >> 2];
          AL.setSourceState(AL.currentCtx.sources[srcId], 4116);
          _alSourcei(srcId, 4105, 0);
          delete AL.currentCtx.sources[srcId];
          AL.freeIds.push(srcId)
        }
      }

      function _alGenBuffers(count, pBufferIds) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(19, 1, count, pBufferIds);
        if (!AL.currentCtx) {
          return
        }
        for (var i = 0; i < count; ++i) {
          var buf = {
            deviceId: AL.currentCtx.deviceId,
            id: AL.newId(),
            refCount: 0,
            audioBuf: null,
            frequency: 0,
            bytesPerSample: 2,
            channels: 1,
            length: 0
          };
          AL.deviceRefCounts[buf.deviceId]++;
          AL.buffers[buf.id] = buf;
          GROWABLE_HEAP_I32()[pBufferIds + i * 4 >> 2] = buf.id
        }
      }

      function _alGenSources(count, pSourceIds) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(20, 1, count, pSourceIds);
        if (!AL.currentCtx) {
          return
        }
        for (var i = 0; i < count; ++i) {
          var gain = AL.currentCtx.audioCtx.createGain();
          gain.connect(AL.currentCtx.gain);
          var src = {
            context: AL.currentCtx,
            id: AL.newId(),
            type: 4144,
            state: 4113,
            bufQueue: [AL.buffers[0]],
            audioQueue: [],
            looping: false,
            pitch: 1,
            dopplerShift: 1,
            gain: gain,
            minGain: 0,
            maxGain: 1,
            panner: null,
            bufsProcessed: 0,
            bufStartTime: Number.NEGATIVE_INFINITY,
            bufOffset: 0,
            relative: false,
            refDistance: 1,
            maxDistance: 340282e33,
            rolloffFactor: 1,
            position: [0, 0, 0],
            velocity: [0, 0, 0],
            direction: [0, 0, 0],
            coneOuterGain: 0,
            coneInnerAngle: 360,
            coneOuterAngle: 360,
            distanceModel: 53250,
            spatialize: 2,
            get playbackRate() {
              return this.pitch * this.dopplerShift
            }
          };
          AL.currentCtx.sources[src.id] = src;
          GROWABLE_HEAP_I32()[pSourceIds + i * 4 >> 2] = src.id
        }
      }

      function _alGetError() {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(21, 1);
        if (!AL.currentCtx) {
          return 40964
        }
        var err = AL.currentCtx.err;
        AL.currentCtx.err = 0;
        return err
      }

      function _alGetSourcef(sourceId, param, pValue) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(22, 1, sourceId, param, pValue);
        var val = AL.getSourceParam("alGetSourcef", sourceId, param);
        if (val === null) {
          return
        }
        if (!pValue) {
          AL.currentCtx.err = 40963;
          return
        }
        switch (param) {
          case 4097:
          case 4098:
          case 4099:
          case 4106:
          case 4109:
          case 4110:
          case 4128:
          case 4129:
          case 4130:
          case 4131:
          case 4132:
          case 4133:
          case 4134:
          case 8203:
            GROWABLE_HEAP_F32()[pValue >> 2] = val;
            break;
          default:
            AL.currentCtx.err = 40962;
            return
        }
      }

      function _alGetSourcei(sourceId, param, pValue) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(23, 1, sourceId, param, pValue);
        var val = AL.getSourceParam("alGetSourcei", sourceId, param);
        if (val === null) {
          return
        }
        if (!pValue) {
          AL.currentCtx.err = 40963;
          return
        }
        switch (param) {
          case 514:
          case 4097:
          case 4098:
          case 4103:
          case 4105:
          case 4112:
          case 4117:
          case 4118:
          case 4128:
          case 4129:
          case 4131:
          case 4132:
          case 4133:
          case 4134:
          case 4135:
          case 4628:
          case 8201:
          case 8202:
          case 53248:
            GROWABLE_HEAP_I32()[pValue >> 2] = val;
            break;
          default:
            AL.currentCtx.err = 40962;
            return
        }
      }

      function _alListenerfv(param, pValues) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(24, 1, param, pValues);
        if (!AL.currentCtx) {
          return
        }
        if (!pValues) {
          AL.currentCtx.err = 40963;
          return
        }
        switch (param) {
          case 4100:
          case 4102:
            AL.paramArray[0] = GROWABLE_HEAP_F32()[pValues >> 2];
            AL.paramArray[1] = GROWABLE_HEAP_F32()[pValues + 4 >> 2];
            AL.paramArray[2] = GROWABLE_HEAP_F32()[pValues + 8 >> 2];
            AL.setListenerParam("alListenerfv", param, AL.paramArray);
            break;
          case 4111:
            AL.paramArray[0] = GROWABLE_HEAP_F32()[pValues >> 2];
            AL.paramArray[1] = GROWABLE_HEAP_F32()[pValues + 4 >> 2];
            AL.paramArray[2] = GROWABLE_HEAP_F32()[pValues + 8 >> 2];
            AL.paramArray[3] = GROWABLE_HEAP_F32()[pValues + 12 >> 2];
            AL.paramArray[4] = GROWABLE_HEAP_F32()[pValues + 16 >> 2];
            AL.paramArray[5] = GROWABLE_HEAP_F32()[pValues + 20 >> 2];
            AL.setListenerParam("alListenerfv", param, AL.paramArray);
            break;
          default:
            AL.setListenerParam("alListenerfv", param, null);
            break
        }
      }

      function _alSourcePlay(sourceId) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(25, 1, sourceId);
        if (!AL.currentCtx) {
          return
        }
        var src = AL.currentCtx.sources[sourceId];
        if (!src) {
          AL.currentCtx.err = 40961;
          return
        }
        AL.setSourceState(src, 4114)
      }

      function _alSourceQueueBuffers(sourceId, count, pBufferIds) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(26, 1, sourceId, count, pBufferIds);
        if (!AL.currentCtx) {
          return
        }
        var src = AL.currentCtx.sources[sourceId];
        if (!src) {
          AL.currentCtx.err = 40961;
          return
        }
        if (src.type === 4136) {
          AL.currentCtx.err = 40964;
          return
        }
        if (count === 0) {
          return
        }
        var templateBuf = AL.buffers[0];
        for (var i = 0; i < src.bufQueue.length; i++) {
          if (src.bufQueue[i].id !== 0) {
            templateBuf = src.bufQueue[i];
            break
          }
        }
        for (var i = 0; i < count; ++i) {
          var bufId = GROWABLE_HEAP_I32()[pBufferIds + i * 4 >> 2];
          var buf = AL.buffers[bufId];
          if (!buf) {
            AL.currentCtx.err = 40961;
            return
          }
          if (templateBuf.id !== 0 && (buf.frequency !== templateBuf.frequency || buf.bytesPerSample !==
              templateBuf.bytesPerSample || buf.channels !== templateBuf.channels)) {
            AL.currentCtx.err = 40964
          }
        }
        if (src.bufQueue.length === 1 && src.bufQueue[0].id === 0) {
          src.bufQueue.length = 0
        }
        src.type = 4137;
        for (var i = 0; i < count; ++i) {
          var bufId = GROWABLE_HEAP_I32()[pBufferIds + i * 4 >> 2];
          var buf = AL.buffers[bufId];
          buf.refCount++;
          src.bufQueue.push(buf)
        }
        if (src.looping) {
          AL.cancelPendingSourceAudio(src)
        }
        AL.initSourcePanner(src);
        AL.scheduleSourceAudio(src)
      }

      function _alSourceStop(sourceId) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(27, 1, sourceId);
        if (!AL.currentCtx) {
          return
        }
        var src = AL.currentCtx.sources[sourceId];
        if (!src) {
          AL.currentCtx.err = 40961;
          return
        }
        AL.setSourceState(src, 4116)
      }

      function _alSourceUnqueueBuffers(sourceId, count, pBufferIds) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(28, 1, sourceId, count, pBufferIds);
        if (!AL.currentCtx) {
          return
        }
        var src = AL.currentCtx.sources[sourceId];
        if (!src) {
          AL.currentCtx.err = 40961;
          return
        }
        if (count > (src.bufQueue.length === 1 && src.bufQueue[0].id === 0 ? 0 : src.bufsProcessed)) {
          AL.currentCtx.err = 40963;
          return
        }
        if (count === 0) {
          return
        }
        for (var i = 0; i < count; i++) {
          var buf = src.bufQueue.shift();
          buf.refCount--;
          GROWABLE_HEAP_I32()[pBufferIds + i * 4 >> 2] = buf.id;
          src.bufsProcessed--
        }
        if (src.bufQueue.length === 0) {
          src.bufQueue.push(AL.buffers[0])
        }
        AL.initSourcePanner(src);
        AL.scheduleSourceAudio(src)
      }

      function _alSourcef(sourceId, param, value) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(29, 1, sourceId, param, value);
        switch (param) {
          case 4097:
          case 4098:
          case 4099:
          case 4106:
          case 4109:
          case 4110:
          case 4128:
          case 4129:
          case 4130:
          case 4131:
          case 4132:
          case 4133:
          case 4134:
          case 8203:
            AL.setSourceParam("alSourcef", sourceId, param, value);
            break;
          default:
            AL.setSourceParam("alSourcef", sourceId, param, null);
            break
        }
      }

      function _alSourcefv(sourceId, param, pValues) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(30, 1, sourceId, param, pValues);
        if (!AL.currentCtx) {
          return
        }
        if (!pValues) {
          AL.currentCtx.err = 40963;
          return
        }
        switch (param) {
          case 4097:
          case 4098:
          case 4099:
          case 4106:
          case 4109:
          case 4110:
          case 4128:
          case 4129:
          case 4130:
          case 4131:
          case 4132:
          case 4133:
          case 4134:
          case 8203:
            var val = GROWABLE_HEAP_F32()[pValues >> 2];
            AL.setSourceParam("alSourcefv", sourceId, param, val);
            break;
          case 4100:
          case 4101:
          case 4102:
            AL.paramArray[0] = GROWABLE_HEAP_F32()[pValues >> 2];
            AL.paramArray[1] = GROWABLE_HEAP_F32()[pValues + 4 >> 2];
            AL.paramArray[2] = GROWABLE_HEAP_F32()[pValues + 8 >> 2];
            AL.setSourceParam("alSourcefv", sourceId, param, AL.paramArray);
            break;
          default:
            AL.setSourceParam("alSourcefv", sourceId, param, null);
            break
        }
      }
      var listenOnce = (object, event, func) => {
        object.addEventListener(event, func, {
          "once": true
        })
      };
      var autoResumeAudioContext = (ctx, elements) => {
        if (!elements) {
          elements = [document, document.getElementById("canvas")]
        } ["keydown", "mousedown", "touchstart"].forEach(event => {
          elements.forEach(element => {
            if (element) {
              listenOnce(element, event, () => {
                if (ctx.state === "suspended") ctx.resume()
              })
            }
          })
        })
      };

      function _alcCreateContext(deviceId, pAttrList) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(31, 1, deviceId, pAttrList);
        if (!(deviceId in AL.deviceRefCounts)) {
          AL.alcErr = 40961;
          return 0
        }
        var options = null;
        var attrs = [];
        var hrtf = null;
        pAttrList >>= 2;
        if (pAttrList) {
          var attr = 0;
          var val = 0;
          while (true) {
            attr = GROWABLE_HEAP_I32()[pAttrList++];
            attrs.push(attr);
            if (attr === 0) {
              break
            }
            val = GROWABLE_HEAP_I32()[pAttrList++];
            attrs.push(val);
            switch (attr) {
              case 4103:
                if (!options) {
                  options = {}
                }
                options.sampleRate = val;
                break;
              case 4112:
              case 4113:
                break;
              case 6546:
                switch (val) {
                  case 0:
                    hrtf = false;
                    break;
                  case 1:
                    hrtf = true;
                    break;
                  case 2:
                    break;
                  default:
                    AL.alcErr = 40964;
                    return 0
                }
                break;
              case 6550:
                if (val !== 0) {
                  AL.alcErr = 40964;
                  return 0
                }
                break;
              default:
                AL.alcErr = 40964;
                return 0
            }
          }
        }
        var AudioContext = window.AudioContext || window.webkitAudioContext;
        var ac = null;
        try {
          if (options) {
            ac = new AudioContext(options)
          } else {
            ac = new AudioContext
          }
        } catch (e) {
          if (e.name === "NotSupportedError") {
            AL.alcErr = 40964
          } else {
            AL.alcErr = 40961
          }
          return 0
        }
        autoResumeAudioContext(ac);
        if (typeof ac.createGain == "undefined") {
          ac.createGain = ac.createGainNode
        }
        var gain = ac.createGain();
        gain.connect(ac.destination);
        var ctx = {
          deviceId: deviceId,
          id: AL.newId(),
          attrs: attrs,
          audioCtx: ac,
          listener: {
            position: [0, 0, 0],
            velocity: [0, 0, 0],
            direction: [0, 0, 0],
            up: [0, 0, 0]
          },
          sources: [],
          interval: setInterval(function() {
            AL.scheduleContextAudio(ctx)
          }, AL.QUEUE_INTERVAL),
          gain: gain,
          distanceModel: 53250,
          speedOfSound: 343.3,
          dopplerFactor: 1,
          sourceDistanceModel: false,
          hrtf: hrtf || false,
          _err: 0,
          get err() {
            return this._err
          },
          set err(val) {
            if (this._err === 0 || val === 0) {
              this._err = val
            }
          }
        };
        AL.deviceRefCounts[deviceId]++;
        AL.contexts[ctx.id] = ctx;
        if (hrtf !== null) {
          for (var ctxId in AL.contexts) {
            var c = AL.contexts[ctxId];
            if (c.deviceId === deviceId) {
              c.hrtf = hrtf;
              AL.updateContextGlobal(c)
            }
          }
        }
        return ctx.id
      }

      function _alcGetCurrentContext() {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(32, 1);
        if (AL.currentCtx !== null) {
          return AL.currentCtx.id
        }
        return 0
      }

      function _alcGetString(deviceId, param) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(33, 1, deviceId, param);
        if (AL.alcStringCache[param]) {
          return AL.alcStringCache[param]
        }
        var ret;
        switch (param) {
          case 0:
            ret = "No Error";
            break;
          case 40961:
            ret = "Invalid Device";
            break;
          case 40962:
            ret = "Invalid Context";
            break;
          case 40963:
            ret = "Invalid Enum";
            break;
          case 40964:
            ret = "Invalid Value";
            break;
          case 40965:
            ret = "Out of Memory";
            break;
          case 4100:
            if (typeof AudioContext != "undefined" || typeof webkitAudioContext != "undefined") {
              ret = AL.DEVICE_NAME
            } else {
              return 0
            }
            break;
          case 4101:
            if (typeof AudioContext != "undefined" || typeof webkitAudioContext != "undefined") {
              ret = AL.DEVICE_NAME.concat("\0")
            } else {
              ret = "\0"
            }
            break;
          case 785:
            ret = AL.CAPTURE_DEVICE_NAME;
            break;
          case 784:
            if (deviceId === 0) ret = AL.CAPTURE_DEVICE_NAME.concat("\0");
            else {
              var c = AL.requireValidCaptureDevice(deviceId, "alcGetString");
              if (!c) {
                return 0
              }
              ret = c.deviceName
            }
            break;
          case 4102:
            if (!deviceId) {
              AL.alcErr = 40961;
              return 0
            }
            ret = "";
            for (var ext in AL.ALC_EXTENSIONS) {
              ret = ret.concat(ext);
              ret = ret.concat(" ")
            }
            ret = ret.trim();
            break;
          default:
            AL.alcErr = 40963;
            return 0
        }
        ret = stringToNewUTF8(ret);
        AL.alcStringCache[param] = ret;
        return ret
      }

      function _alcMakeContextCurrent(contextId) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(34, 1, contextId);
        if (contextId === 0) {
          AL.currentCtx = null
        } else {
          AL.currentCtx = AL.contexts[contextId]
        }
        return 1
      }

      function _alcOpenDevice(pDeviceName) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(35, 1, pDeviceName);
        if (pDeviceName) {
          var name = UTF8ToString(pDeviceName);
          if (name !== AL.DEVICE_NAME) {
            return 0
          }
        }
        if (typeof AudioContext != "undefined" || typeof webkitAudioContext != "undefined") {
          var deviceId = AL.newId();
          AL.deviceRefCounts[deviceId] = 0;
          return deviceId
        }
        return 0
      }
      var readEmAsmArgsArray = [];
      var readEmAsmArgs = (sigPtr, buf) => {
        readEmAsmArgsArray.length = 0;
        var ch;
        buf >>= 2;
        while (ch = GROWABLE_HEAP_U8()[sigPtr++]) {
          buf += ch != 105 & buf;
          readEmAsmArgsArray.push(ch == 105 ? GROWABLE_HEAP_I32()[buf] : GROWABLE_HEAP_F64()[buf++ >> 1]);
          ++buf
        }
        return readEmAsmArgsArray
      };
      var runEmAsmFunction = (code, sigPtr, argbuf) => {
        var args = readEmAsmArgs(sigPtr, argbuf);
        return ASM_CONSTS[code].apply(null, args)
      };
      var _emscripten_asm_const_int = (code, sigPtr, argbuf) => {
        return runEmAsmFunction(code, sigPtr, argbuf)
      };

      function _emscripten_cancel_main_loop() {
        Browser.mainLoop.pause();
        Browser.mainLoop.func = null
      }

      function _emscripten_check_blocking_allowed() {}

      function _emscripten_date_now() {
        return Date.now()
      }
      var _emscripten_exit_with_live_runtime = () => {
        runtimeKeepalivePush();
        throw "unwind"
      };

      function getCanvasSizeCallingThread(target, width, height) {
        var canvas = findCanvasEventTarget(target);
        if (!canvas) return -4;
        if (canvas.canvasSharedPtr) {
          var w = GROWABLE_HEAP_I32()[canvas.canvasSharedPtr >> 2];
          var h = GROWABLE_HEAP_I32()[canvas.canvasSharedPtr + 4 >> 2];
          GROWABLE_HEAP_I32()[width >> 2] = w;
          GROWABLE_HEAP_I32()[height >> 2] = h
        } else if (canvas.offscreenCanvas) {
          GROWABLE_HEAP_I32()[width >> 2] = canvas.offscreenCanvas.width;
          GROWABLE_HEAP_I32()[height >> 2] = canvas.offscreenCanvas.height
        } else if (!canvas.controlTransferredOffscreen) {
          GROWABLE_HEAP_I32()[width >> 2] = canvas.width;
          GROWABLE_HEAP_I32()[height >> 2] = canvas.height
        } else {
          return -4
        }
        return 0
      }

      function getCanvasSizeMainThread(target, width, height) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(36, 1, target, width, height);
        return getCanvasSizeCallingThread(target, width, height)
      }

      function _emscripten_get_canvas_element_size(target, width, height) {
        var canvas = findCanvasEventTarget(target);
        if (canvas) {
          return getCanvasSizeCallingThread(target, width, height)
        }
        return getCanvasSizeMainThread(target, width, height)
      }
      var proxyToMainThread = function(index, sync) {
        var numCallArgs = arguments.length - 2;
        var outerArgs = arguments;
        return withStackSave(() => {
          var serializedNumCallArgs = numCallArgs;
          var args = stackAlloc(serializedNumCallArgs * 8);
          var b = args >> 3;
          for (var i = 0; i < numCallArgs; i++) {
            var arg = outerArgs[2 + i];
            GROWABLE_HEAP_F64()[b + i] = arg
          }
          return __emscripten_run_in_main_runtime_thread_js(index, serializedNumCallArgs, args, sync)
        })
      };
      var emscripten_receive_on_main_thread_js_callArgs = [];

      function _emscripten_receive_on_main_thread_js(index, numCallArgs, args) {
        emscripten_receive_on_main_thread_js_callArgs.length = numCallArgs;
        var b = args >> 3;
        for (var i = 0; i < numCallArgs; i++) {
          emscripten_receive_on_main_thread_js_callArgs[i] = GROWABLE_HEAP_F64()[b + i]
        }
        var isEmAsmConst = index < 0;
        var func = !isEmAsmConst ? proxiedFunctionTable[index] : ASM_CONSTS[-index - 1];
        return func.apply(null, emscripten_receive_on_main_thread_js_callArgs)
      }
      var getHeapMax = () => 1072693248;
      var growMemory = size => {
        var b = wasmMemory.buffer;
        var pages = size - b.byteLength + 65535 >>> 16;
        try {
          wasmMemory.grow(pages);
          updateMemoryViews();
          return 1
        } catch (e) {}
      };
      var _emscripten_resize_heap = requestedSize => {
        var oldSize = GROWABLE_HEAP_U8().length;
        requestedSize = requestedSize >>> 0;
        if (requestedSize <= oldSize) {
          return false
        }
        var maxHeapSize = getHeapMax();
        if (requestedSize > maxHeapSize) {
          return false
        }
        var alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple;
        for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
          var overGrownHeapSize = oldSize * (1 + .2 / cutDown);
          overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
          var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
          var replacement = growMemory(newSize);
          if (replacement) {
            return true
          }
        }
        return false
      };
      var _emscripten_set_main_loop_arg = function(func, arg, fps, simulateInfiniteLoop) {
        var browserIterationFunc = () => getWasmTableEntry(func)(arg);
        setMainLoop(browserIterationFunc, fps, simulateInfiniteLoop, arg)
      };

      function _emscripten_supports_offscreencanvas() {
        return typeof OffscreenCanvas != "undefined"
      }

      function _emscripten_unwind_to_js_event_loop() {
        throw "unwind"
      }

      function _emscripten_webgl_do_commit_frame() {
        if (!GL.currentContext || !GL.currentContext.GLctx) {
          return -3
        }
        if (!GL.currentContext.attributes.explicitSwapControl) {
          return -3
        }
        return 0
      }
      var _emscripten_webgl_commit_frame = _emscripten_webgl_do_commit_frame;
      var emscripten_webgl_power_preferences = ["default", "low-power", "high-performance"];
      var specialHTMLTargets = [0, typeof document != "undefined" ? document : 0, typeof window != "undefined" ?
        window : 0
      ];

      function _emscripten_webgl_do_create_context(target, attributes) {
        var a = attributes >> 2;
        var powerPreference = GROWABLE_HEAP_I32()[a + (24 >> 2)];
        var contextAttributes = {
          "alpha": !!GROWABLE_HEAP_I32()[a + (0 >> 2)],
          "depth": !!GROWABLE_HEAP_I32()[a + (4 >> 2)],
          "stencil": !!GROWABLE_HEAP_I32()[a + (8 >> 2)],
          "antialias": !!GROWABLE_HEAP_I32()[a + (12 >> 2)],
          "premultipliedAlpha": !!GROWABLE_HEAP_I32()[a + (16 >> 2)],
          "preserveDrawingBuffer": !!GROWABLE_HEAP_I32()[a + (20 >> 2)],
          "powerPreference": emscripten_webgl_power_preferences[powerPreference],
          "failIfMajorPerformanceCaveat": !!GROWABLE_HEAP_I32()[a + (28 >> 2)],
          majorVersion: GROWABLE_HEAP_I32()[a + (32 >> 2)],
          minorVersion: GROWABLE_HEAP_I32()[a + (36 >> 2)],
          enableExtensionsByDefault: GROWABLE_HEAP_I32()[a + (40 >> 2)],
          explicitSwapControl: GROWABLE_HEAP_I32()[a + (44 >> 2)],
          proxyContextToMainThread: GROWABLE_HEAP_I32()[a + (48 >> 2)],
          renderViaOffscreenBackBuffer: GROWABLE_HEAP_I32()[a + (52 >> 2)]
        };
        var canvas = findCanvasEventTarget(target);
        if (!canvas) {
          return 0
        }
        if (canvas.offscreenCanvas) canvas = canvas.offscreenCanvas;
        if (contextAttributes.explicitSwapControl) {
          var supportsOffscreenCanvas = canvas.transferControlToOffscreen || typeof OffscreenCanvas !=
            "undefined" && canvas instanceof OffscreenCanvas;
          if (!supportsOffscreenCanvas) {
            return 0
          }
          if (canvas.transferControlToOffscreen) {
            if (!canvas.controlTransferredOffscreen) {
              GL.offscreenCanvases[canvas.id] = {
                canvas: canvas.transferControlToOffscreen(),
                canvasSharedPtr: _malloc(12),
                id: canvas.id
              };
              canvas.controlTransferredOffscreen = true
            } else if (!GL.offscreenCanvases[canvas.id]) {
              return 0
            }
            canvas = GL.offscreenCanvases[canvas.id]
          }
        }
        var contextHandle = GL.createContext(canvas, contextAttributes);
        return contextHandle
      }
      var _emscripten_webgl_create_context = _emscripten_webgl_do_create_context;

      function _emscripten_webgl_destroy_context_calling_thread(contextHandle) {
        if (GL.currentContext == contextHandle) GL.currentContext = 0;
        GL.deleteContext(contextHandle)
      }
      var _emscripten_webgl_destroy_context_main_thread = _emscripten_webgl_destroy_context_calling_thread;

      function _emscripten_webgl_destroy_context(p0) {
        return GL.contexts[p0] ? _emscripten_webgl_destroy_context_calling_thread(p0) :
          _emscripten_webgl_destroy_context_main_thread(p0)
      }

      function _emscripten_webgl_do_get_current_context() {
        return GL.currentContext ? GL.currentContext.handle : 0
      }
      var _emscripten_webgl_get_current_context = _emscripten_webgl_do_get_current_context;

      function _emscripten_webgl_init_context_attributes(attributes) {
        var a = attributes >> 2;
        for (var i = 0; i < 56 >> 2; ++i) {
          GROWABLE_HEAP_I32()[a + i] = 0
        }
        GROWABLE_HEAP_I32()[a + (0 >> 2)] = GROWABLE_HEAP_I32()[a + (4 >> 2)] = GROWABLE_HEAP_I32()[a + (12 >>
          2)] = GROWABLE_HEAP_I32()[a + (16 >> 2)] = GROWABLE_HEAP_I32()[a + (32 >> 2)] = GROWABLE_HEAP_I32()[a +
            (40 >> 2)] = 1;
        if (ENVIRONMENT_IS_WORKER) GROWABLE_HEAP_I32()[attributes + 48 >> 2] = 1
      }

      function _emscripten_webgl_make_context_current(contextHandle) {
        var success = GL.makeContextCurrent(contextHandle);
        return success ? 0 : -5
      }
      var ENV = {};
      var getExecutableName = () => {
        return thisProgram || "./this.program"
      };
      var getEnvStrings = () => {
        if (!getEnvStrings.strings) {
          var lang = (typeof navigator == "object" && navigator.languages && navigator.languages[0] || "C")
            .replace("-", "_") + ".UTF-8";
          var env = {
            "USER": "web_user",
            "LOGNAME": "web_user",
            "PATH": "/",
            "PWD": "/",
            "HOME": "/home/web_user",
            "LANG": lang,
            "_": getExecutableName()
          };
          for (var x in ENV) {
            if (ENV[x] === undefined) delete env[x];
            else env[x] = ENV[x]
          }
          var strings = [];
          for (var x in env) {
            strings.push(`${x}=${env[x]}`)
          }
          getEnvStrings.strings = strings
        }
        return getEnvStrings.strings
      };
      var stringToAscii = (str, buffer) => {
        for (var i = 0; i < str.length; ++i) {
          GROWABLE_HEAP_I8()[buffer++ >> 0] = str.charCodeAt(i)
        }
        GROWABLE_HEAP_I8()[buffer >> 0] = 0
      };

      function _environ_get(__environ, environ_buf) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(37, 1, __environ, environ_buf);
        var bufSize = 0;
        getEnvStrings().forEach(function(string, i) {
          var ptr = environ_buf + bufSize;
          GROWABLE_HEAP_U32()[__environ + i * 4 >> 2] = ptr;
          stringToAscii(string, ptr);
          bufSize += string.length + 1
        });
        return 0
      }

      function _environ_sizes_get(penviron_count, penviron_buf_size) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(38, 1, penviron_count, penviron_buf_size);
        var strings = getEnvStrings();
        GROWABLE_HEAP_U32()[penviron_count >> 2] = strings.length;
        var bufSize = 0;
        strings.forEach(function(string) {
          bufSize += string.length + 1
        });
        GROWABLE_HEAP_U32()[penviron_buf_size >> 2] = bufSize;
        return 0
      }

      function _fd_close(fd) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(39, 1, fd);
        try {
          var stream = SYSCALLS.getStreamFromFD(fd);
          FS.close(stream);
          return 0
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return e.errno
        }
      }
      var doReadv = (stream, iov, iovcnt, offset) => {
        var ret = 0;
        for (var i = 0; i < iovcnt; i++) {
          var ptr = GROWABLE_HEAP_U32()[iov >> 2];
          var len = GROWABLE_HEAP_U32()[iov + 4 >> 2];
          iov += 8;
          var curr = FS.read(stream, GROWABLE_HEAP_I8(), ptr, len, offset);
          if (curr < 0) return -1;
          ret += curr;
          if (curr < len) break;
          if (typeof offset !== "undefined") {
            offset += curr
          }
        }
        return ret
      };

      function _fd_read(fd, iov, iovcnt, pnum) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(40, 1, fd, iov, iovcnt, pnum);
        try {
          var stream = SYSCALLS.getStreamFromFD(fd);
          var num = doReadv(stream, iov, iovcnt);
          GROWABLE_HEAP_U32()[pnum >> 2] = num;
          return 0
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return e.errno
        }
      }

      function convertI32PairToI53Checked(lo, hi) {
        return hi + 2097152 >>> 0 < 4194305 - !!lo ? (lo >>> 0) + hi * 4294967296 : NaN
      }

      function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(41, 1, fd, offset_low, offset_high, whence,
          newOffset);
        try {
          var offset = convertI32PairToI53Checked(offset_low, offset_high);
          if (isNaN(offset)) return 61;
          var stream = SYSCALLS.getStreamFromFD(fd);
          FS.llseek(stream, offset, whence);
          tempI64 = [stream.position >>> 0, (tempDouble = stream.position, +Math.abs(tempDouble) >= 1 ?
              tempDouble > 0 ? +Math.floor(tempDouble / 4294967296) >>> 0 : ~~+Math.ceil((tempDouble - +(~~
                tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[newOffset >> 2] = tempI64[0],
            GROWABLE_HEAP_I32()[newOffset + 4 >> 2] = tempI64[1];
          if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null;
          return 0
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return e.errno
        }
      }
      var doWritev = (stream, iov, iovcnt, offset) => {
        var ret = 0;
        for (var i = 0; i < iovcnt; i++) {
          var ptr = GROWABLE_HEAP_U32()[iov >> 2];
          var len = GROWABLE_HEAP_U32()[iov + 4 >> 2];
          iov += 8;
          var curr = FS.write(stream, GROWABLE_HEAP_I8(), ptr, len, offset);
          if (curr < 0) return -1;
          ret += curr;
          if (typeof offset !== "undefined") {
            offset += curr
          }
        }
        return ret
      };

      function _fd_write(fd, iov, iovcnt, pnum) {
        if (ENVIRONMENT_IS_PTHREAD) return proxyToMainThread(42, 1, fd, iov, iovcnt, pnum);
        try {
          var stream = SYSCALLS.getStreamFromFD(fd);
          var num = doWritev(stream, iov, iovcnt);
          GROWABLE_HEAP_U32()[pnum >> 2] = num;
          return 0
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return e.errno
        }
      }

      function _glActiveTexture(x0) {
        GLctx.activeTexture(x0)
      }

      function _glAttachShader(program, shader) {
        GLctx.attachShader(GL.programs[program], GL.shaders[shader])
      }

      function _glBindBuffer(target, buffer) {
        if (target == 35051) {
          GLctx.currentPixelPackBufferBinding = buffer
        } else if (target == 35052) {
          GLctx.currentPixelUnpackBufferBinding = buffer
        }
        GLctx.bindBuffer(target, GL.buffers[buffer])
      }

      function _glBindFramebuffer(target, framebuffer) {
        GLctx.bindFramebuffer(target, GL.framebuffers[framebuffer])
      }

      function _glBindTexture(target, texture) {
        GLctx.bindTexture(target, GL.textures[texture])
      }

      function _glBlendFunc(x0, x1) {
        GLctx.blendFunc(x0, x1)
      }

      function _glBufferData(target, size, data, usage) {
        if (GL.currentContext.version >= 2) {
          if (data && size) {
            GLctx.bufferData(target, GROWABLE_HEAP_U8(), usage, data, size)
          } else {
            GLctx.bufferData(target, size, usage)
          }
        } else {
          GLctx.bufferData(target, data ? GROWABLE_HEAP_U8().subarray(data, data + size) : size, usage)
        }
      }

      function _glClear(x0) {
        GLctx.clear(x0)
      }

      function _glCompileShader(shader) {
        GLctx.compileShader(GL.shaders[shader])
      }

      function _glCreateProgram() {
        var id = GL.getNewId(GL.programs);
        var program = GLctx.createProgram();
        program.name = id;
        program.maxUniformLength = program.maxAttributeLength = program.maxUniformBlockNameLength = 0;
        program.uniformIdCounter = 1;
        GL.programs[id] = program;
        return id
      }

      function _glCreateShader(shaderType) {
        var id = GL.getNewId(GL.shaders);
        GL.shaders[id] = GLctx.createShader(shaderType);
        return id
      }

      function _glDeleteBuffers(n, buffers) {
        for (var i = 0; i < n; i++) {
          var id = GROWABLE_HEAP_I32()[buffers + i * 4 >> 2];
          var buffer = GL.buffers[id];
          if (!buffer) continue;
          GLctx.deleteBuffer(buffer);
          buffer.name = 0;
          GL.buffers[id] = null;
          if (id == GLctx.currentPixelPackBufferBinding) GLctx.currentPixelPackBufferBinding = 0;
          if (id == GLctx.currentPixelUnpackBufferBinding) GLctx.currentPixelUnpackBufferBinding = 0
        }
      }

      function _glDeleteFramebuffers(n, framebuffers) {
        for (var i = 0; i < n; ++i) {
          var id = GROWABLE_HEAP_I32()[framebuffers + i * 4 >> 2];
          var framebuffer = GL.framebuffers[id];
          if (!framebuffer) continue;
          GLctx.deleteFramebuffer(framebuffer);
          framebuffer.name = 0;
          GL.framebuffers[id] = null
        }
      }

      function _glDeleteProgram(id) {
        if (!id) return;
        var program = GL.programs[id];
        if (!program) {
          GL.recordError(1281);
          return
        }
        GLctx.deleteProgram(program);
        program.name = 0;
        GL.programs[id] = null
      }

      function _glDeleteRenderbuffers(n, renderbuffers) {
        for (var i = 0; i < n; i++) {
          var id = GROWABLE_HEAP_I32()[renderbuffers + i * 4 >> 2];
          var renderbuffer = GL.renderbuffers[id];
          if (!renderbuffer) continue;
          GLctx.deleteRenderbuffer(renderbuffer);
          renderbuffer.name = 0;
          GL.renderbuffers[id] = null
        }
      }

      function _glDeleteShader(id) {
        if (!id) return;
        var shader = GL.shaders[id];
        if (!shader) {
          GL.recordError(1281);
          return
        }
        GLctx.deleteShader(shader);
        GL.shaders[id] = null
      }

      function _glDeleteTextures(n, textures) {
        for (var i = 0; i < n; i++) {
          var id = GROWABLE_HEAP_I32()[textures + i * 4 >> 2];
          var texture = GL.textures[id];
          if (!texture) continue;
          GLctx.deleteTexture(texture);
          texture.name = 0;
          GL.textures[id] = null
        }
      }

      function _glDepthFunc(x0) {
        GLctx.depthFunc(x0)
      }

      function _glDepthMask(flag) {
        GLctx.depthMask(!!flag)
      }

      function _glDetachShader(program, shader) {
        GLctx.detachShader(GL.programs[program], GL.shaders[shader])
      }

      function _glDisable(x0) {
        GLctx.disable(x0)
      }

      function _glDisableVertexAttribArray(index) {
        GLctx.disableVertexAttribArray(index)
      }

      function _glDrawArrays(mode, first, count) {
        GLctx.drawArrays(mode, first, count)
      }

      function _glEnable(x0) {
        GLctx.enable(x0)
      }

      function _glEnableVertexAttribArray(index) {
        GLctx.enableVertexAttribArray(index)
      }

      function _glFramebufferTexture2D(target, attachment, textarget, texture, level) {
        GLctx.framebufferTexture2D(target, attachment, textarget, GL.textures[texture], level)
      }

      function __glGenObject(n, buffers, createFunction, objectTable) {
        for (var i = 0; i < n; i++) {
          var buffer = GLctx[createFunction]();
          var id = buffer && GL.getNewId(objectTable);
          if (buffer) {
            buffer.name = id;
            objectTable[id] = buffer
          } else {
            GL.recordError(1282)
          }
          GROWABLE_HEAP_I32()[buffers + i * 4 >> 2] = id
        }
      }

      function _glGenBuffers(n, buffers) {
        __glGenObject(n, buffers, "createBuffer", GL.buffers)
      }

      function _glGenFramebuffers(n, ids) {
        __glGenObject(n, ids, "createFramebuffer", GL.framebuffers)
      }

      function _glGenTextures(n, textures) {
        __glGenObject(n, textures, "createTexture", GL.textures)
      }

      function _glGenerateMipmap(x0) {
        GLctx.generateMipmap(x0)
      }

      function _glGetAttribLocation(program, name) {
        return GLctx.getAttribLocation(GL.programs[program], UTF8ToString(name))
      }

      function writeI53ToI64(ptr, num) {
        GROWABLE_HEAP_U32()[ptr >> 2] = num;
        GROWABLE_HEAP_U32()[ptr + 4 >> 2] = (num - GROWABLE_HEAP_U32()[ptr >> 2]) / 4294967296
      }

      function emscriptenWebGLGet(name_, p, type) {
        if (!p) {
          GL.recordError(1281);
          return
        }
        var ret = undefined;
        switch (name_) {
          case 36346:
            ret = 1;
            break;
          case 36344:
            if (type != 0 && type != 1) {
              GL.recordError(1280)
            }
            return;
          case 34814:
          case 36345:
            ret = 0;
            break;
          case 34466:
            var formats = GLctx.getParameter(34467);
            ret = formats ? formats.length : 0;
            break;
          case 33309:
            if (GL.currentContext.version < 2) {
              GL.recordError(1282);
              return
            }
            var exts = GLctx.getSupportedExtensions() || [];
            ret = 2 * exts.length;
            break;
          case 33307:
          case 33308:
            if (GL.currentContext.version < 2) {
              GL.recordError(1280);
              return
            }
            ret = name_ == 33307 ? 3 : 0;
            break
        }
        if (ret === undefined) {
          var result = GLctx.getParameter(name_);
          switch (typeof result) {
            case "number":
              ret = result;
              break;
            case "boolean":
              ret = result ? 1 : 0;
              break;
            case "string":
              GL.recordError(1280);
              return;
            case "object":
              if (result === null) {
                switch (name_) {
                  case 34964:
                  case 35725:
                  case 34965:
                  case 36006:
                  case 36007:
                  case 32873:
                  case 34229:
                  case 36662:
                  case 36663:
                  case 35053:
                  case 35055:
                  case 36010:
                  case 35097:
                  case 35869:
                  case 32874:
                  case 36389:
                  case 35983:
                  case 35368:
                  case 34068: {
                    ret = 0;
                    break
                  }
                  default: {
                    GL.recordError(1280);
                    return
                  }
                }
              } else if (result instanceof Float32Array || result instanceof Uint32Array ||
                result instanceof Int32Array || result instanceof Array) {
                for (var i = 0; i < result.length; ++i) {
                  switch (type) {
                    case 0:
                      GROWABLE_HEAP_I32()[p + i * 4 >> 2] = result[i];
                      break;
                    case 2:
                      GROWABLE_HEAP_F32()[p + i * 4 >> 2] = result[i];
                      break;
                    case 4:
                      GROWABLE_HEAP_I8()[p + i >> 0] = result[i] ? 1 : 0;
                      break
                  }
                }
                return
              } else {
                try {
                  ret = result.name | 0
                } catch (e) {
                  GL.recordError(1280);
                  err("GL_INVALID_ENUM in glGet" + type + "v: Unknown object returned from WebGL getParameter(" +
                    name_ + ")! (error: " + e + ")");
                  return
                }
              }
              break;
            default:
              GL.recordError(1280);
              err("GL_INVALID_ENUM in glGet" + type + "v: Native code calling glGet" + type + "v(" + name_ +
                ") and it returns " + result + " of type " + typeof result + "!");
              return
          }
        }
        switch (type) {
          case 1:
            writeI53ToI64(p, ret);
            break;
          case 0:
            GROWABLE_HEAP_I32()[p >> 2] = ret;
            break;
          case 2:
            GROWABLE_HEAP_F32()[p >> 2] = ret;
            break;
          case 4:
            GROWABLE_HEAP_I8()[p >> 0] = ret ? 1 : 0;
            break
        }
      }

      function _glGetIntegerv(name_, p) {
        emscriptenWebGLGet(name_, p, 0)
      }

      function _glGetProgramiv(program, pname, p) {
        if (!p) {
          GL.recordError(1281);
          return
        }
        if (program >= GL.counter) {
          GL.recordError(1281);
          return
        }
        program = GL.programs[program];
        if (pname == 35716) {
          var log = GLctx.getProgramInfoLog(program);
          if (log === null) log = "(unknown error)";
          GROWABLE_HEAP_I32()[p >> 2] = log.length + 1
        } else if (pname == 35719) {
          if (!program.maxUniformLength) {
            for (var i = 0; i < GLctx.getProgramParameter(program, 35718); ++i) {
              program.maxUniformLength = Math.max(program.maxUniformLength, GLctx.getActiveUniform(program, i)
                .name.length + 1)
            }
          }
          GROWABLE_HEAP_I32()[p >> 2] = program.maxUniformLength
        } else if (pname == 35722) {
          if (!program.maxAttributeLength) {
            for (var i = 0; i < GLctx.getProgramParameter(program, 35721); ++i) {
              program.maxAttributeLength = Math.max(program.maxAttributeLength, GLctx.getActiveAttrib(program, i)
                .name.length + 1)
            }
          }
          GROWABLE_HEAP_I32()[p >> 2] = program.maxAttributeLength
        } else if (pname == 35381) {
          if (!program.maxUniformBlockNameLength) {
            for (var i = 0; i < GLctx.getProgramParameter(program, 35382); ++i) {
              program.maxUniformBlockNameLength = Math.max(program.maxUniformBlockNameLength, GLctx
                .getActiveUniformBlockName(program, i).length + 1)
            }
          }
          GROWABLE_HEAP_I32()[p >> 2] = program.maxUniformBlockNameLength
        } else {
          GROWABLE_HEAP_I32()[p >> 2] = GLctx.getProgramParameter(program, pname)
        }
      }

      function _glGetShaderInfoLog(shader, maxLength, length, infoLog) {
        var log = GLctx.getShaderInfoLog(GL.shaders[shader]);
        if (log === null) log = "(unknown error)";
        var numBytesWrittenExclNull = maxLength > 0 && infoLog ? stringToUTF8(log, infoLog, maxLength) : 0;
        if (length) GROWABLE_HEAP_I32()[length >> 2] = numBytesWrittenExclNull
      }

      function _glGetShaderiv(shader, pname, p) {
        if (!p) {
          GL.recordError(1281);
          return
        }
        if (pname == 35716) {
          var log = GLctx.getShaderInfoLog(GL.shaders[shader]);
          if (log === null) log = "(unknown error)";
          var logLength = log ? log.length + 1 : 0;
          GROWABLE_HEAP_I32()[p >> 2] = logLength
        } else if (pname == 35720) {
          var source = GLctx.getShaderSource(GL.shaders[shader]);
          var sourceLength = source ? source.length + 1 : 0;
          GROWABLE_HEAP_I32()[p >> 2] = sourceLength
        } else {
          GROWABLE_HEAP_I32()[p >> 2] = GLctx.getShaderParameter(GL.shaders[shader], pname)
        }
      }
      var jstoi_q = str => parseInt(str);

      function webglGetLeftBracePos(name) {
        return name.slice(-1) == "]" && name.lastIndexOf("[")
      }

      function webglPrepareUniformLocationsBeforeFirstUse(program) {
        var uniformLocsById = program.uniformLocsById,
          uniformSizeAndIdsByName = program.uniformSizeAndIdsByName,
          i, j;
        if (!uniformLocsById) {
          program.uniformLocsById = uniformLocsById = {};
          program.uniformArrayNamesById = {};
          for (i = 0; i < GLctx.getProgramParameter(program, 35718); ++i) {
            var u = GLctx.getActiveUniform(program, i);
            var nm = u.name;
            var sz = u.size;
            var lb = webglGetLeftBracePos(nm);
            var arrayName = lb > 0 ? nm.slice(0, lb) : nm;
            var id = program.uniformIdCounter;
            program.uniformIdCounter += sz;
            uniformSizeAndIdsByName[arrayName] = [sz, id];
            for (j = 0; j < sz; ++j) {
              uniformLocsById[id] = j;
              program.uniformArrayNamesById[id++] = arrayName
            }
          }
        }
      }

      function _glGetUniformLocation(program, name) {
        name = UTF8ToString(name);
        if (program = GL.programs[program]) {
          webglPrepareUniformLocationsBeforeFirstUse(program);
          var uniformLocsById = program.uniformLocsById;
          var arrayIndex = 0;
          var uniformBaseName = name;
          var leftBrace = webglGetLeftBracePos(name);
          if (leftBrace > 0) {
            arrayIndex = jstoi_q(name.slice(leftBrace + 1)) >>> 0;
            uniformBaseName = name.slice(0, leftBrace)
          }
          var sizeAndId = program.uniformSizeAndIdsByName[uniformBaseName];
          if (sizeAndId && arrayIndex < sizeAndId[0]) {
            arrayIndex += sizeAndId[1];
            if (uniformLocsById[arrayIndex] = uniformLocsById[arrayIndex] || GLctx.getUniformLocation(program,
                name)) {
              return arrayIndex
            }
          }
        } else {
          GL.recordError(1281)
        }
        return -1
      }

      function _glLinkProgram(program) {
        program = GL.programs[program];
        GLctx.linkProgram(program);
        program.uniformLocsById = 0;
        program.uniformSizeAndIdsByName = {}
      }

      function _glScissor(x0, x1, x2, x3) {
        GLctx.scissor(x0, x1, x2, x3)
      }

      function _glShaderSource(shader, count, string, length) {
        var source = GL.getSource(shader, count, string, length);
        GLctx.shaderSource(GL.shaders[shader], source)
      }

      function computeUnpackAlignedImageSize(width, height, sizePerPixel, alignment) {
        function roundedToNextMultipleOf(x, y) {
          return x + y - 1 & -y
        }
        var plainRowSize = width * sizePerPixel;
        var alignedRowSize = roundedToNextMultipleOf(plainRowSize, alignment);
        return height * alignedRowSize
      }

      function colorChannelsInGlTextureFormat(format) {
        var colorChannels = {
          5: 3,
          6: 4,
          8: 2,
          29502: 3,
          29504: 4,
          26917: 2,
          26918: 2,
          29846: 3,
          29847: 4
        };
        return colorChannels[format - 6402] || 1
      }

      function heapObjectForWebGLType(type) {
        type -= 5120;
        if (type == 0) return GROWABLE_HEAP_I8();
        if (type == 1) return GROWABLE_HEAP_U8();
        if (type == 2) return GROWABLE_HEAP_I16();
        if (type == 4) return GROWABLE_HEAP_I32();
        if (type == 6) return GROWABLE_HEAP_F32();
        if (type == 5 || type == 28922 || type == 28520 || type == 30779 || type == 30782)
        return GROWABLE_HEAP_U32();
        return GROWABLE_HEAP_U16()
      }

      function heapAccessShiftForWebGLHeap(heap) {
        return 31 - Math.clz32(heap.BYTES_PER_ELEMENT)
      }

      function emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, internalFormat) {
        var heap = heapObjectForWebGLType(type);
        var shift = heapAccessShiftForWebGLHeap(heap);
        var byteSize = 1 << shift;
        var sizePerPixel = colorChannelsInGlTextureFormat(format) * byteSize;
        var bytes = computeUnpackAlignedImageSize(width, height, sizePerPixel, GL.unpackAlignment);
        return heap.subarray(pixels >> shift, pixels + bytes >> shift)
      }

      function _glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels) {
        if (GL.currentContext.version >= 2) {
          if (GLctx.currentPixelUnpackBufferBinding) {
            GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels)
          } else if (pixels) {
            var heap = heapObjectForWebGLType(type);
            GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, heap, pixels >>
              heapAccessShiftForWebGLHeap(heap))
          } else {
            GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, null)
          }
          return
        }
        GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels ?
          emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, internalFormat) : null)
      }

      function _glTexParameteri(x0, x1, x2) {
        GLctx.texParameteri(x0, x1, x2)
      }

      function webglGetUniformLocation(location) {
        var p = GLctx.currentProgram;
        if (p) {
          var webglLoc = p.uniformLocsById[location];
          if (typeof webglLoc == "number") {
            p.uniformLocsById[location] = webglLoc = GLctx.getUniformLocation(p, p.uniformArrayNamesById[
              location] + (webglLoc > 0 ? "[" + webglLoc + "]" : ""))
          }
          return webglLoc
        } else {
          GL.recordError(1282)
        }
      }

      function _glUniform1f(location, v0) {
        GLctx.uniform1f(webglGetUniformLocation(location), v0)
      }

      function _glUniform1i(location, v0) {
        GLctx.uniform1i(webglGetUniformLocation(location), v0)
      }

      function _glUniform4f(location, v0, v1, v2, v3) {
        GLctx.uniform4f(webglGetUniformLocation(location), v0, v1, v2, v3)
      }
      var miniTempWebGLFloatBuffers = [];

      function _glUniformMatrix4fv(location, count, transpose, value) {
        if (GL.currentContext.version >= 2) {
          count && GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, GROWABLE_HEAP_F32(),
            value >> 2, count * 16);
          return
        }
        if (count <= 18) {
          var view = miniTempWebGLFloatBuffers[16 * count - 1];
          var heap = GROWABLE_HEAP_F32();
          value >>= 2;
          for (var i = 0; i < 16 * count; i += 16) {
            var dst = value + i;
            view[i] = heap[dst];
            view[i + 1] = heap[dst + 1];
            view[i + 2] = heap[dst + 2];
            view[i + 3] = heap[dst + 3];
            view[i + 4] = heap[dst + 4];
            view[i + 5] = heap[dst + 5];
            view[i + 6] = heap[dst + 6];
            view[i + 7] = heap[dst + 7];
            view[i + 8] = heap[dst + 8];
            view[i + 9] = heap[dst + 9];
            view[i + 10] = heap[dst + 10];
            view[i + 11] = heap[dst + 11];
            view[i + 12] = heap[dst + 12];
            view[i + 13] = heap[dst + 13];
            view[i + 14] = heap[dst + 14];
            view[i + 15] = heap[dst + 15]
          }
        } else {
          var view = GROWABLE_HEAP_F32().subarray(value >> 2, value + count * 64 >> 2)
        }
        GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, view)
      }

      function _glUseProgram(program) {
        program = GL.programs[program];
        GLctx.useProgram(program);
        GLctx.currentProgram = program
      }

      function _glVertexAttribPointer(index, size, type, normalized, stride, ptr) {
        GLctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr)
      }

      function _glViewport(x0, x1, x2, x3) {
        GLctx.viewport(x0, x1, x2, x3)
      }

      function getCFunc(ident) {
        var func = Module["_" + ident];
        return func
      }
      var writeArrayToMemory = (array, buffer) => {
        GROWABLE_HEAP_I8().set(array, buffer)
      };
      var stringToUTF8OnStack = str => {
        var size = lengthBytesUTF8(str) + 1;
        var ret = stackAlloc(size);
        stringToUTF8(str, ret, size);
        return ret
      };
      var ccall = function(ident, returnType, argTypes, args, opts) {
        var toC = {
          "string": str => {
            var ret = 0;
            if (str !== null && str !== undefined && str !== 0) {
              ret = stringToUTF8OnStack(str)
            }
            return ret
          },
          "array": arr => {
            var ret = stackAlloc(arr.length);
            writeArrayToMemory(arr, ret);
            return ret
          }
        };

        function convertReturnValue(ret) {
          if (returnType === "string") {
            return UTF8ToString(ret)
          }
          if (returnType === "boolean") return Boolean(ret);
          return ret
        }
        var func = getCFunc(ident);
        var cArgs = [];
        var stack = 0;
        if (args) {
          for (var i = 0; i < args.length; i++) {
            var converter = toC[argTypes[i]];
            if (converter) {
              if (stack === 0) stack = stackSave();
              cArgs[i] = converter(args[i])
            } else {
              cArgs[i] = args[i]
            }
          }
        }
        var ret = func.apply(null, cArgs);

        function onDone(ret) {
          if (stack !== 0) stackRestore(stack);
          return convertReturnValue(ret)
        }
        ret = onDone(ret);
        return ret
      };

      function uleb128Encode(n, target) {
        if (n < 128) {
          target.push(n)
        } else {
          target.push(n % 128 | 128, n >> 7)
        }
      }

      function sigToWasmTypes(sig) {
        var typeNames = {
          "i": "i32",
          "j": "i64",
          "f": "f32",
          "d": "f64",
          "p": "i32"
        };
        var type = {
          parameters: [],
          results: sig[0] == "v" ? [] : [typeNames[sig[0]]]
        };
        for (var i = 1; i < sig.length; ++i) {
          type.parameters.push(typeNames[sig[i]])
        }
        return type
      }

      function generateFuncType(sig, target) {
        var sigRet = sig.slice(0, 1);
        var sigParam = sig.slice(1);
        var typeCodes = {
          "i": 127,
          "p": 127,
          "j": 126,
          "f": 125,
          "d": 124
        };
        target.push(96);
        uleb128Encode(sigParam.length, target);
        for (var i = 0; i < sigParam.length; ++i) {
          target.push(typeCodes[sigParam[i]])
        }
        if (sigRet == "v") {
          target.push(0)
        } else {
          target.push(1, typeCodes[sigRet])
        }
      }

      function convertJsFunctionToWasm(func, sig) {
        if (typeof WebAssembly.Function == "function") {
          return new WebAssembly.Function(sigToWasmTypes(sig), func)
        }
        var typeSectionBody = [1];
        generateFuncType(sig, typeSectionBody);
        var bytes = [0, 97, 115, 109, 1, 0, 0, 0, 1];
        uleb128Encode(typeSectionBody.length, bytes);
        bytes.push.apply(bytes, typeSectionBody);
        bytes.push(2, 7, 1, 1, 101, 1, 102, 0, 0, 7, 5, 1, 1, 102, 0, 0);
        var module = new WebAssembly.Module(new Uint8Array(bytes));
        var instance = new WebAssembly.Instance(module, {
          "e": {
            "f": func
          }
        });
        var wrappedFunc = instance.exports["f"];
        return wrappedFunc
      }

      function updateTableMap(offset, count) {
        if (functionsInTableMap) {
          for (var i = offset; i < offset + count; i++) {
            var item = getWasmTableEntry(i);
            if (item) {
              functionsInTableMap.set(item, i)
            }
          }
        }
      }
      var functionsInTableMap = undefined;

      function getFunctionAddress(func) {
        if (!functionsInTableMap) {
          functionsInTableMap = new WeakMap;
          updateTableMap(0, wasmTable.length)
        }
        return functionsInTableMap.get(func) || 0
      }
      var freeTableIndexes = [];

      function getEmptyTableSlot() {
        if (freeTableIndexes.length) {
          return freeTableIndexes.pop()
        }
        try {
          wasmTable.grow(1)
        } catch (err) {
          if (!(err instanceof RangeError)) {
            throw err
          }
          throw "Unable to grow wasm table. Set ALLOW_TABLE_GROWTH."
        }
        return wasmTable.length - 1
      }
      var setWasmTableEntry = (idx, func) => {
        wasmTable.set(idx, func);
        wasmTableMirror[idx] = wasmTable.get(idx)
      };

      function addFunction(func, sig) {
        var rtn = getFunctionAddress(func);
        if (rtn) {
          return rtn
        }
        var ret = getEmptyTableSlot();
        try {
          setWasmTableEntry(ret, func)
        } catch (err) {
          if (!(err instanceof TypeError)) {
            throw err
          }
          var wrapped = convertJsFunctionToWasm(func, sig);
          setWasmTableEntry(ret, wrapped)
        }
        functionsInTableMap.set(func, ret);
        return ret
      }
      PThread.init();
      var FSNode = function(parent, name, mode, rdev) {
        if (!parent) {
          parent = this
        }
        this.parent = parent;
        this.mount = parent.mount;
        this.mounted = null;
        this.id = FS.nextInode++;
        this.name = name;
        this.mode = mode;
        this.node_ops = {};
        this.stream_ops = {};
        this.rdev = rdev
      };
      var readMode = 292 | 73;
      var writeMode = 146;
      Object.defineProperties(FSNode.prototype, {
        read: {
          get: function() {
            return (this.mode & readMode) === readMode
          },
          set: function(val) {
            val ? this.mode |= readMode : this.mode &= ~readMode
          }
        },
        write: {
          get: function() {
            return (this.mode & writeMode) === writeMode
          },
          set: function(val) {
            val ? this.mode |= writeMode : this.mode &= ~writeMode
          }
        },
        isFolder: {
          get: function() {
            return FS.isDir(this.mode)
          }
        },
        isDevice: {
          get: function() {
            return FS.isChrdev(this.mode)
          }
        }
      });
      FS.FSNode = FSNode;
      FS.createPreloadedFile = FS_createPreloadedFile;
      FS.staticInit();
      Module["FS_createPath"] = FS.createPath;
      Module["FS_createDataFile"] = FS.createDataFile;
      Module["FS_createPreloadedFile"] = FS.createPreloadedFile;
      Module["FS_unlink"] = FS.unlink;
      Module["FS_createLazyFile"] = FS.createLazyFile;
      Module["FS_createDevice"] = FS.createDevice;
      embind_init_charCodes();
      BindingError = Module["BindingError"] = extendError(Error, "BindingError");
      InternalError = Module["InternalError"] = extendError(Error, "InternalError");
      init_emval();
      var GLctx;
      Module["requestFullscreen"] = function Module_requestFullscreen(lockPointer, resizeCanvas) {
        Browser.requestFullscreen(lockPointer, resizeCanvas)
      };
      Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) {
        Browser.requestAnimationFrame(func)
      };
      Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) {
        Browser.setCanvasSize(width, height, noUpdates)
      };
      Module["pauseMainLoop"] = function Module_pauseMainLoop() {
        Browser.mainLoop.pause()
      };
      Module["resumeMainLoop"] = function Module_resumeMainLoop() {
        Browser.mainLoop.resume()
      };
      Module["getUserMedia"] = function Module_getUserMedia() {
        Browser.getUserMedia()
      };
      Module["createContext"] = function Module_createContext(canvas, useWebGL, setInModule,
        webGLContextAttributes) {
        return Browser.createContext(canvas, useWebGL, setInModule, webGLContextAttributes)
      };
      var preloadedImages = {};
      var preloadedAudios = {};
      var miniTempWebGLFloatBuffersStorage = new Float32Array(288);
      for (var i = 0; i < 288; ++i) {
        miniTempWebGLFloatBuffers[i] = miniTempWebGLFloatBuffersStorage.subarray(0, i + 1)
      }
      var proxiedFunctionTable = [null, _proc_exit, exitOnMainThread, _AdditionDataCB, _DecCB, _FirstFrameCB,
        _PrivateInfoCB, _RawDataCB, _RunTimeInfoCB, _YUVDisplayCB, pthreadCreateProxied, ___syscall_fcntl64,
        ___syscall_ioctl, ___syscall_openat, setCanvasElementSizeMainThread, _alBufferData, _alDeleteBuffers,
        _alDeleteSources, _alSourcei, _alGenBuffers, _alGenSources, _alGetError, _alGetSourcef, _alGetSourcei,
        _alListenerfv, _alSourcePlay, _alSourceQueueBuffers, _alSourceStop, _alSourceUnqueueBuffers, _alSourcef,
        _alSourcefv, _alcCreateContext, _alcGetCurrentContext, _alcGetString, _alcMakeContextCurrent,
        _alcOpenDevice, getCanvasSizeMainThread, _environ_get, _environ_sizes_get, _fd_close, _fd_read,
        _fd_seek, _fd_write
      ];
      var wasmImports = {
        "AdditionDataCB": _AdditionDataCB,
        "DecCB": _DecCB,
        "FirstFrameCB": _FirstFrameCB,
        "PrivateInfoCB": _PrivateInfoCB,
        "RawDataCB": _RawDataCB,
        "RunTimeInfoCB": _RunTimeInfoCB,
        "YUVDisplayCB": _YUVDisplayCB,
        "__assert_fail": ___assert_fail,
        "__cxa_throw": ___cxa_throw,
        "__emscripten_init_main_thread_js": ___emscripten_init_main_thread_js,
        "__emscripten_thread_cleanup": ___emscripten_thread_cleanup,
        "__pthread_create_js": ___pthread_create_js,
        "__syscall_fcntl64": ___syscall_fcntl64,
        "__syscall_ioctl": ___syscall_ioctl,
        "__syscall_openat": ___syscall_openat,
        "_embind_register_bigint": __embind_register_bigint,
        "_embind_register_bool": __embind_register_bool,
        "_embind_register_emval": __embind_register_emval,
        "_embind_register_float": __embind_register_float,
        "_embind_register_integer": __embind_register_integer,
        "_embind_register_memory_view": __embind_register_memory_view,
        "_embind_register_std_string": __embind_register_std_string,
        "_embind_register_std_wstring": __embind_register_std_wstring,
        "_embind_register_void": __embind_register_void,
        "_emscripten_fs_load_embedded_files": __emscripten_fs_load_embedded_files,
        "_emscripten_get_now_is_monotonic": __emscripten_get_now_is_monotonic,
        "_emscripten_notify_mailbox_postmessage": __emscripten_notify_mailbox_postmessage,
        "_emscripten_set_offscreencanvas_size": __emscripten_set_offscreencanvas_size,
        "_emscripten_thread_mailbox_await": __emscripten_thread_mailbox_await,
        "_emscripten_thread_set_strongref": __emscripten_thread_set_strongref,
        "_emscripten_throw_longjmp": __emscripten_throw_longjmp,
        "_localtime_js": __localtime_js,
        "_tzset_js": __tzset_js,
        "abort": _abort,
        "alBufferData": _alBufferData,
        "alDeleteBuffers": _alDeleteBuffers,
        "alDeleteSources": _alDeleteSources,
        "alGenBuffers": _alGenBuffers,
        "alGenSources": _alGenSources,
        "alGetError": _alGetError,
        "alGetSourcef": _alGetSourcef,
        "alGetSourcei": _alGetSourcei,
        "alListenerfv": _alListenerfv,
        "alSourcePlay": _alSourcePlay,
        "alSourceQueueBuffers": _alSourceQueueBuffers,
        "alSourceStop": _alSourceStop,
        "alSourceUnqueueBuffers": _alSourceUnqueueBuffers,
        "alSourcef": _alSourcef,
        "alSourcefv": _alSourcefv,
        "alSourcei": _alSourcei,
        "alcCreateContext": _alcCreateContext,
        "alcGetCurrentContext": _alcGetCurrentContext,
        "alcGetString": _alcGetString,
        "alcMakeContextCurrent": _alcMakeContextCurrent,
        "alcOpenDevice": _alcOpenDevice,
        "emscripten_asm_const_int": _emscripten_asm_const_int,
        "emscripten_cancel_main_loop": _emscripten_cancel_main_loop,
        "emscripten_check_blocking_allowed": _emscripten_check_blocking_allowed,
        "emscripten_date_now": _emscripten_date_now,
        "emscripten_exit_with_live_runtime": _emscripten_exit_with_live_runtime,
        "emscripten_get_canvas_element_size": _emscripten_get_canvas_element_size,
        "emscripten_get_now": _emscripten_get_now,
        "emscripten_receive_on_main_thread_js": _emscripten_receive_on_main_thread_js,
        "emscripten_resize_heap": _emscripten_resize_heap,
        "emscripten_set_canvas_element_size": _emscripten_set_canvas_element_size,
        "emscripten_set_main_loop_arg": _emscripten_set_main_loop_arg,
        "emscripten_supports_offscreencanvas": _emscripten_supports_offscreencanvas,
        "emscripten_unwind_to_js_event_loop": _emscripten_unwind_to_js_event_loop,
        "emscripten_webgl_commit_frame": _emscripten_webgl_commit_frame,
        "emscripten_webgl_create_context": _emscripten_webgl_create_context,
        "emscripten_webgl_destroy_context": _emscripten_webgl_destroy_context,
        "emscripten_webgl_get_current_context": _emscripten_webgl_get_current_context,
        "emscripten_webgl_init_context_attributes": _emscripten_webgl_init_context_attributes,
        "emscripten_webgl_make_context_current": _emscripten_webgl_make_context_current,
        "environ_get": _environ_get,
        "environ_sizes_get": _environ_sizes_get,
        "exit": _exit,
        "fd_close": _fd_close,
        "fd_read": _fd_read,
        "fd_seek": _fd_seek,
        "fd_write": _fd_write,
        "glActiveTexture": _glActiveTexture,
        "glAttachShader": _glAttachShader,
        "glBindBuffer": _glBindBuffer,
        "glBindFramebuffer": _glBindFramebuffer,
        "glBindTexture": _glBindTexture,
        "glBlendFunc": _glBlendFunc,
        "glBufferData": _glBufferData,
        "glClear": _glClear,
        "glCompileShader": _glCompileShader,
        "glCreateProgram": _glCreateProgram,
        "glCreateShader": _glCreateShader,
        "glDeleteBuffers": _glDeleteBuffers,
        "glDeleteFramebuffers": _glDeleteFramebuffers,
        "glDeleteProgram": _glDeleteProgram,
        "glDeleteRenderbuffers": _glDeleteRenderbuffers,
        "glDeleteShader": _glDeleteShader,
        "glDeleteTextures": _glDeleteTextures,
        "glDepthFunc": _glDepthFunc,
        "glDepthMask": _glDepthMask,
        "glDetachShader": _glDetachShader,
        "glDisable": _glDisable,
        "glDisableVertexAttribArray": _glDisableVertexAttribArray,
        "glDrawArrays": _glDrawArrays,
        "glEnable": _glEnable,
        "glEnableVertexAttribArray": _glEnableVertexAttribArray,
        "glFramebufferTexture2D": _glFramebufferTexture2D,
        "glGenBuffers": _glGenBuffers,
        "glGenFramebuffers": _glGenFramebuffers,
        "glGenTextures": _glGenTextures,
        "glGenerateMipmap": _glGenerateMipmap,
        "glGetAttribLocation": _glGetAttribLocation,
        "glGetIntegerv": _glGetIntegerv,
        "glGetProgramiv": _glGetProgramiv,
        "glGetShaderInfoLog": _glGetShaderInfoLog,
        "glGetShaderiv": _glGetShaderiv,
        "glGetUniformLocation": _glGetUniformLocation,
        "glLinkProgram": _glLinkProgram,
        "glScissor": _glScissor,
        "glShaderSource": _glShaderSource,
        "glTexImage2D": _glTexImage2D,
        "glTexParameteri": _glTexParameteri,
        "glUniform1f": _glUniform1f,
        "glUniform1i": _glUniform1i,
        "glUniform4f": _glUniform4f,
        "glUniformMatrix4fv": _glUniformMatrix4fv,
        "glUseProgram": _glUseProgram,
        "glVertexAttribPointer": _glVertexAttribPointer,
        "glViewport": _glViewport,
        "invoke_iii": invoke_iii,
        "invoke_iiii": invoke_iiii,
        "invoke_iiiii": invoke_iiiii,
        "invoke_vi": invoke_vi,
        "invoke_viiii": invoke_viiii,
        "memory": wasmMemory || Module["wasmMemory"]
      };
      var asm = createWasm();
      var ___wasm_call_ctors = function() {
        return (___wasm_call_ctors = Module["asm"]["__wasm_call_ctors"]).apply(null, arguments)
      };
      var _DecCallBack = Module["_DecCallBack"] = function() {
        return (_DecCallBack = Module["_DecCallBack"] = Module["asm"]["DecCallBack"]).apply(null, arguments)
      };
      var _DisplayCallBack = Module["_DisplayCallBack"] = function() {
        return (_DisplayCallBack = Module["_DisplayCallBack"] = Module["asm"]["DisplayCallBack"]).apply(null,
          arguments)
      };
      var _RawDataCallBack = Module["_RawDataCallBack"] = function() {
        return (_RawDataCallBack = Module["_RawDataCallBack"] = Module["asm"]["RawDataCallBack"]).apply(null,
          arguments)
      };
      var _FrameInfoCallBack = Module["_FrameInfoCallBack"] = function() {
        return (_FrameInfoCallBack = Module["_FrameInfoCallBack"] = Module["asm"]["FrameInfoCallBack"]).apply(
          null, arguments)
      };
      var _PrivateInfoCBFun = Module["_PrivateInfoCBFun"] = function() {
        return (_PrivateInfoCBFun = Module["_PrivateInfoCBFun"] = Module["asm"]["PrivateInfoCBFun"]).apply(null,
          arguments)
      };
      var _getTotalMemory = Module["_getTotalMemory"] = function() {
        return (_getTotalMemory = Module["_getTotalMemory"] = Module["asm"]["getTotalMemory"]).apply(null,
          arguments)
      };
      var _getFreeMemory = Module["_getFreeMemory"] = function() {
        return (_getFreeMemory = Module["_getFreeMemory"] = Module["asm"]["getFreeMemory"]).apply(null,
          arguments)
      };
      var _AdditionDataCBFun = Module["_AdditionDataCBFun"] = function() {
        return (_AdditionDataCBFun = Module["_AdditionDataCBFun"] = Module["asm"]["AdditionDataCBFun"]).apply(
          null, arguments)
      };
      var _RunTimeInfoCBFun = Module["_RunTimeInfoCBFun"] = function() {
        return (_RunTimeInfoCBFun = Module["_RunTimeInfoCBFun"] = Module["asm"]["RunTimeInfoCBFun"]).apply(null,
          arguments)
      };
      var _JSPlayM4_GetFrameInfo = Module["_JSPlayM4_GetFrameInfo"] = function() {
        return (_JSPlayM4_GetFrameInfo = Module["_JSPlayM4_GetFrameInfo"] = Module["asm"][
          "JSPlayM4_GetFrameInfo"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetPort = Module["_JSPlayM4_GetPort"] = function() {
        return (_JSPlayM4_GetPort = Module["_JSPlayM4_GetPort"] = Module["asm"]["JSPlayM4_GetPort"]).apply(null,
          arguments)
      };
      var _JSPlayM4_SetStreamOpenMode = Module["_JSPlayM4_SetStreamOpenMode"] = function() {
        return (_JSPlayM4_SetStreamOpenMode = Module["_JSPlayM4_SetStreamOpenMode"] = Module["asm"][
          "JSPlayM4_SetStreamOpenMode"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_OpenStream = Module["_JSPlayM4_OpenStream"] = function() {
        return (_JSPlayM4_OpenStream = Module["_JSPlayM4_OpenStream"] = Module["asm"]["JSPlayM4_OpenStream"])
          .apply(null, arguments)
      };
      var _JSPlayM4_SetFirstFrameCallBack = Module["_JSPlayM4_SetFirstFrameCallBack"] = function() {
        return (_JSPlayM4_SetFirstFrameCallBack = Module["_JSPlayM4_SetFirstFrameCallBack"] = Module["asm"][
          "JSPlayM4_SetFirstFrameCallBack"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetDecCallBack = Module["_JSPlayM4_SetDecCallBack"] = function() {
        return (_JSPlayM4_SetDecCallBack = Module["_JSPlayM4_SetDecCallBack"] = Module["asm"][
          "JSPlayM4_SetDecCallBack"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetDisplayCallBack = Module["_JSPlayM4_SetDisplayCallBack"] = function() {
        return (_JSPlayM4_SetDisplayCallBack = Module["_JSPlayM4_SetDisplayCallBack"] = Module["asm"][
          "JSPlayM4_SetDisplayCallBack"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetFrameInfoCallBack = Module["_JSPlayM4_SetFrameInfoCallBack"] = function() {
        return (_JSPlayM4_SetFrameInfoCallBack = Module["_JSPlayM4_SetFrameInfoCallBack"] = Module["asm"][
          "JSPlayM4_SetFrameInfoCallBack"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetResetCallBack = Module["_JSPlayM4_SetResetCallBack"] = function() {
        return (_JSPlayM4_SetResetCallBack = Module["_JSPlayM4_SetResetCallBack"] = Module["asm"][
          "JSPlayM4_SetResetCallBack"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetVideoRawDataCallBack0 = Module["_JSPlayM4_SetVideoRawDataCallBack0"] = function() {
        return (_JSPlayM4_SetVideoRawDataCallBack0 = Module["_JSPlayM4_SetVideoRawDataCallBack0"] = Module[
          "asm"]["JSPlayM4_SetVideoRawDataCallBack0"]).apply(null, arguments)
      };
      var _JSPlayM4_SetVideoRawDataCallBack = Module["_JSPlayM4_SetVideoRawDataCallBack"] = function() {
        return (_JSPlayM4_SetVideoRawDataCallBack = Module["_JSPlayM4_SetVideoRawDataCallBack"] = Module["asm"][
          "JSPlayM4_SetVideoRawDataCallBack"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetDecCBStream = Module["_JSPlayM4_SetDecCBStream"] = function() {
        return (_JSPlayM4_SetDecCBStream = Module["_JSPlayM4_SetDecCBStream"] = Module["asm"][
          "JSPlayM4_SetDecCBStream"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_Play = Module["_JSPlayM4_Play"] = function() {
        return (_JSPlayM4_Play = Module["_JSPlayM4_Play"] = Module["asm"]["JSPlayM4_Play"]).apply(null,
          arguments)
      };
      var _JSPlayM4_InputData = Module["_JSPlayM4_InputData"] = function() {
        return (_JSPlayM4_InputData = Module["_JSPlayM4_InputData"] = Module["asm"]["JSPlayM4_InputData"])
          .apply(null, arguments)
      };
      var _JSPlayM4_Stop = Module["_JSPlayM4_Stop"] = function() {
        return (_JSPlayM4_Stop = Module["_JSPlayM4_Stop"] = Module["asm"]["JSPlayM4_Stop"]).apply(null,
          arguments)
      };
      var _JSPlayM4_CloseStream = Module["_JSPlayM4_CloseStream"] = function() {
        return (_JSPlayM4_CloseStream = Module["_JSPlayM4_CloseStream"] = Module["asm"]["JSPlayM4_CloseStream"])
          .apply(null, arguments)
      };
      var _JSPlayM4_FreePort = Module["_JSPlayM4_FreePort"] = function() {
        return (_JSPlayM4_FreePort = Module["_JSPlayM4_FreePort"] = Module["asm"]["JSPlayM4_FreePort"]).apply(
          null, arguments)
      };
      var _JSPlayM4_SetDecodeFrameType = Module["_JSPlayM4_SetDecodeFrameType"] = function() {
        return (_JSPlayM4_SetDecodeFrameType = Module["_JSPlayM4_SetDecodeFrameType"] = Module["asm"][
          "JSPlayM4_SetDecodeFrameType"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_PlaySound = Module["_JSPlayM4_PlaySound"] = function() {
        return (_JSPlayM4_PlaySound = Module["_JSPlayM4_PlaySound"] = Module["asm"]["JSPlayM4_PlaySound"])
          .apply(null, arguments)
      };
      var _JSPlayM4_SetSecretKey = Module["_JSPlayM4_SetSecretKey"] = function() {
        return (_JSPlayM4_SetSecretKey = Module["_JSPlayM4_SetSecretKey"] = Module["asm"][
          "JSPlayM4_SetSecretKey"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetJPEG = Module["_JSPlayM4_GetJPEG"] = function() {
        return (_JSPlayM4_GetJPEG = Module["_JSPlayM4_GetJPEG"] = Module["asm"]["JSPlayM4_GetJPEG"]).apply(null,
          arguments)
      };
      var _JSPlayM4_GetBMP = Module["_JSPlayM4_GetBMP"] = function() {
        return (_JSPlayM4_GetBMP = Module["_JSPlayM4_GetBMP"] = Module["asm"]["JSPlayM4_GetBMP"]).apply(null,
          arguments)
      };
      var _JSPlayM4_GetCropJPEG = Module["_JSPlayM4_GetCropJPEG"] = function() {
        return (_JSPlayM4_GetCropJPEG = Module["_JSPlayM4_GetCropJPEG"] = Module["asm"]["JSPlayM4_GetCropJPEG"])
          .apply(null, arguments)
      };
      var _JSPlayM4_GetCropBMP = Module["_JSPlayM4_GetCropBMP"] = function() {
        return (_JSPlayM4_GetCropBMP = Module["_JSPlayM4_GetCropBMP"] = Module["asm"]["JSPlayM4_GetCropBMP"])
          .apply(null, arguments)
      };
      var _JSPlayM4_StopSound = Module["_JSPlayM4_StopSound"] = function() {
        return (_JSPlayM4_StopSound = Module["_JSPlayM4_StopSound"] = Module["asm"]["JSPlayM4_StopSound"])
          .apply(null, arguments)
      };
      var _JSPlayM4_GetSDKVersion = Module["_JSPlayM4_GetSDKVersion"] = function() {
        return (_JSPlayM4_GetSDKVersion = Module["_JSPlayM4_GetSDKVersion"] = Module["asm"][
          "JSPlayM4_GetSDKVersion"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetBuildDate = Module["_JSPlayM4_GetBuildDate"] = function() {
        return (_JSPlayM4_GetBuildDate = Module["_JSPlayM4_GetBuildDate"] = Module["asm"][
          "JSPlayM4_GetBuildDate"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetLastError = Module["_JSPlayM4_GetLastError"] = function() {
        return (_JSPlayM4_GetLastError = Module["_JSPlayM4_GetLastError"] = Module["asm"][
          "JSPlayM4_GetLastError"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_Fast = Module["_JSPlayM4_Fast"] = function() {
        return (_JSPlayM4_Fast = Module["_JSPlayM4_Fast"] = Module["asm"]["JSPlayM4_Fast"]).apply(null,
          arguments)
      };
      var _JSPlayM4_Slow = Module["_JSPlayM4_Slow"] = function() {
        return (_JSPlayM4_Slow = Module["_JSPlayM4_Slow"] = Module["asm"]["JSPlayM4_Slow"]).apply(null,
          arguments)
      };
      var _JSPlayM4_SetIFrameDecInterval = Module["_JSPlayM4_SetIFrameDecInterval"] = function() {
        return (_JSPlayM4_SetIFrameDecInterval = Module["_JSPlayM4_SetIFrameDecInterval"] = Module["asm"][
          "JSPlayM4_SetIFrameDecInterval"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetDecodeThread = Module["_JSPlayM4_SetDecodeThread"] = function() {
        return (_JSPlayM4_SetDecodeThread = Module["_JSPlayM4_SetDecodeThread"] = Module["asm"][
          "JSPlayM4_SetDecodeThread"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_Pause = Module["_JSPlayM4_Pause"] = function() {
        return (_JSPlayM4_Pause = Module["_JSPlayM4_Pause"] = Module["asm"]["JSPlayM4_Pause"]).apply(null,
          arguments)
      };
      var _JSPlayM4_OneByOne = Module["_JSPlayM4_OneByOne"] = function() {
        return (_JSPlayM4_OneByOne = Module["_JSPlayM4_OneByOne"] = Module["asm"]["JSPlayM4_OneByOne"]).apply(
          null, arguments)
      };
      var _JSPlayM4_SetVolume = Module["_JSPlayM4_SetVolume"] = function() {
        return (_JSPlayM4_SetVolume = Module["_JSPlayM4_SetVolume"] = Module["asm"]["JSPlayM4_SetVolume"])
          .apply(null, arguments)
      };
      var _JSPlayM4_GetVolume = Module["_JSPlayM4_GetVolume"] = function() {
        return (_JSPlayM4_GetVolume = Module["_JSPlayM4_GetVolume"] = Module["asm"]["JSPlayM4_GetVolume"])
          .apply(null, arguments)
      };
      var _JSPlayM4_SetDisplayRegion = Module["_JSPlayM4_SetDisplayRegion"] = function() {
        return (_JSPlayM4_SetDisplayRegion = Module["_JSPlayM4_SetDisplayRegion"] = Module["asm"][
          "JSPlayM4_SetDisplayRegion"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetPrintLogFlag = Module["_JSPlayM4_SetPrintLogFlag"] = function() {
        return (_JSPlayM4_SetPrintLogFlag = Module["_JSPlayM4_SetPrintLogFlag"] = Module["asm"][
          "JSPlayM4_SetPrintLogFlag"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_RenderPrivateData = Module["_JSPlayM4_RenderPrivateData"] = function() {
        return (_JSPlayM4_RenderPrivateData = Module["_JSPlayM4_RenderPrivateData"] = Module["asm"][
          "JSPlayM4_RenderPrivateData"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_RenderPrivateDataEx = Module["_JSPlayM4_RenderPrivateDataEx"] = function() {
        return (_JSPlayM4_RenderPrivateDataEx = Module["_JSPlayM4_RenderPrivateDataEx"] = Module["asm"][
          "JSPlayM4_RenderPrivateDataEx"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetCanvasSize = Module["_JSPlayM4_SetCanvasSize"] = function() {
        return (_JSPlayM4_SetCanvasSize = Module["_JSPlayM4_SetCanvasSize"] = Module["asm"][
          "JSPlayM4_SetCanvasSize"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetDisplayBuf = Module["_JSPlayM4_SetDisplayBuf"] = function() {
        return (_JSPlayM4_SetDisplayBuf = Module["_JSPlayM4_SetDisplayBuf"] = Module["asm"][
          "JSPlayM4_SetDisplayBuf"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetAudioDisplayBuf = Module["_JSPlayM4_SetAudioDisplayBuf"] = function() {
        return (_JSPlayM4_SetAudioDisplayBuf = Module["_JSPlayM4_SetAudioDisplayBuf"] = Module["asm"][
          "JSPlayM4_SetAudioDisplayBuf"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetSourceBufferRemain = Module["_JSPlayM4_GetSourceBufferRemain"] = function() {
        return (_JSPlayM4_GetSourceBufferRemain = Module["_JSPlayM4_GetSourceBufferRemain"] = Module["asm"][
          "JSPlayM4_GetSourceBufferRemain"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetBufferValue = Module["_JSPlayM4_GetBufferValue"] = function() {
        return (_JSPlayM4_GetBufferValue = Module["_JSPlayM4_GetBufferValue"] = Module["asm"][
          "JSPlayM4_GetBufferValue"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_ReversePlay = Module["_JSPlayM4_ReversePlay"] = function() {
        return (_JSPlayM4_ReversePlay = Module["_JSPlayM4_ReversePlay"] = Module["asm"]["JSPlayM4_ReversePlay"])
          .apply(null, arguments)
      };
      var _JSPlayM4_SetDecodeThreadNum = Module["_JSPlayM4_SetDecodeThreadNum"] = function() {
        return (_JSPlayM4_SetDecodeThreadNum = Module["_JSPlayM4_SetDecodeThreadNum"] = Module["asm"][
          "JSPlayM4_SetDecodeThreadNum"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetCanvasSize = Module["_JSPlayM4_GetCanvasSize"] = function() {
        return (_JSPlayM4_GetCanvasSize = Module["_JSPlayM4_GetCanvasSize"] = Module["asm"][
          "JSPlayM4_GetCanvasSize"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_DisplayLostFrames = Module["_JSPlayM4_DisplayLostFrames"] = function() {
        return (_JSPlayM4_DisplayLostFrames = Module["_JSPlayM4_DisplayLostFrames"] = Module["asm"][
          "JSPlayM4_DisplayLostFrames"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetANRParam = Module["_JSPlayM4_SetANRParam"] = function() {
        return (_JSPlayM4_SetANRParam = Module["_JSPlayM4_SetANRParam"] = Module["asm"]["JSPlayM4_SetANRParam"])
          .apply(null, arguments)
      };
      var _JSPlayM4_SetResampleValue = Module["_JSPlayM4_SetResampleValue"] = function() {
        return (_JSPlayM4_SetResampleValue = Module["_JSPlayM4_SetResampleValue"] = Module["asm"][
          "JSPlayM4_SetResampleValue"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetAntialias = Module["_JSPlayM4_SetAntialias"] = function() {
        return (_JSPlayM4_SetAntialias = Module["_JSPlayM4_SetAntialias"] = Module["asm"][
          "JSPlayM4_SetAntialias"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SyncToAudio = Module["_JSPlayM4_SyncToAudio"] = function() {
        return (_JSPlayM4_SyncToAudio = Module["_JSPlayM4_SyncToAudio"] = Module["asm"]["JSPlayM4_SyncToAudio"])
          .apply(null, arguments)
      };
      var _JSPlayM4_SetAudioThreadModel = Module["_JSPlayM4_SetAudioThreadModel"] = function() {
        return (_JSPlayM4_SetAudioThreadModel = Module["_JSPlayM4_SetAudioThreadModel"] = Module["asm"][
          "JSPlayM4_SetAudioThreadModel"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetDecodeERC = Module["_JSPlayM4_SetDecodeERC"] = function() {
        return (_JSPlayM4_SetDecodeERC = Module["_JSPlayM4_SetDecodeERC"] = Module["asm"][
          "JSPlayM4_SetDecodeERC"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SkipErrorData = Module["_JSPlayM4_SkipErrorData"] = function() {
        return (_JSPlayM4_SkipErrorData = Module["_JSPlayM4_SkipErrorData"] = Module["asm"][
          "JSPlayM4_SkipErrorData"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetAdditionDataCallBack = Module["_JSPlayM4_SetAdditionDataCallBack"] = function() {
        return (_JSPlayM4_SetAdditionDataCallBack = Module["_JSPlayM4_SetAdditionDataCallBack"] = Module["asm"][
          "JSPlayM4_SetAdditionDataCallBack"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetAdditionData = Module["_JSPlayM4_GetAdditionData"] = function() {
        return (_JSPlayM4_GetAdditionData = Module["_JSPlayM4_GetAdditionData"] = Module["asm"][
          "JSPlayM4_GetAdditionData"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetDemuxModel = Module["_JSPlayM4_SetDemuxModel"] = function() {
        return (_JSPlayM4_SetDemuxModel = Module["_JSPlayM4_SetDemuxModel"] = Module["asm"][
          "JSPlayM4_SetDemuxModel"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetD3DPostProcess = Module["_JSPlayM4_SetD3DPostProcess"] = function() {
        return (_JSPlayM4_SetD3DPostProcess = Module["_JSPlayM4_SetD3DPostProcess"] = Module["asm"][
          "JSPlayM4_SetD3DPostProcess"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetDecodeEngine = Module["_JSPlayM4_SetDecodeEngine"] = function() {
        return (_JSPlayM4_SetDecodeEngine = Module["_JSPlayM4_SetDecodeEngine"] = Module["asm"][
          "JSPlayM4_SetDecodeEngine"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetGlobalBaseTime = Module["_JSPlayM4_SetGlobalBaseTime"] = function() {
        return (_JSPlayM4_SetGlobalBaseTime = Module["_JSPlayM4_SetGlobalBaseTime"] = Module["asm"][
          "JSPlayM4_SetGlobalBaseTime"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetPlayedTimeEx = Module["_JSPlayM4_GetPlayedTimeEx"] = function() {
        return (_JSPlayM4_GetPlayedTimeEx = Module["_JSPlayM4_GetPlayedTimeEx"] = Module["asm"][
          "JSPlayM4_GetPlayedTimeEx"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetFileTime = Module["_JSPlayM4_GetFileTime"] = function() {
        return (_JSPlayM4_GetFileTime = Module["_JSPlayM4_GetFileTime"] = Module["asm"]["JSPlayM4_GetFileTime"])
          .apply(null, arguments)
      };
      var _JSPlayM4_GetMpOffset = Module["_JSPlayM4_GetMpOffset"] = function() {
        return (_JSPlayM4_GetMpOffset = Module["_JSPlayM4_GetMpOffset"] = Module["asm"]["JSPlayM4_GetMpOffset"])
          .apply(null, arguments)
      };
      var _JSPlayM4_ResetBuffer = Module["_JSPlayM4_ResetBuffer"] = function() {
        return (_JSPlayM4_ResetBuffer = Module["_JSPlayM4_ResetBuffer"] = Module["asm"]["JSPlayM4_ResetBuffer"])
          .apply(null, arguments)
      };
      var _JSPlayM4_ResetEnd = Module["_JSPlayM4_ResetEnd"] = function() {
        return (_JSPlayM4_ResetEnd = Module["_JSPlayM4_ResetEnd"] = Module["asm"]["JSPlayM4_ResetEnd"]).apply(
          null, arguments)
      };
      var _JSPlayM4_IgnoreHeaderAudioDefine = Module["_JSPlayM4_IgnoreHeaderAudioDefine"] = function() {
        return (_JSPlayM4_IgnoreHeaderAudioDefine = Module["_JSPlayM4_IgnoreHeaderAudioDefine"] = Module["asm"][
          "JSPlayM4_IgnoreHeaderAudioDefine"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetSycGroup = Module["_JSPlayM4_SetSycGroup"] = function() {
        return (_JSPlayM4_SetSycGroup = Module["_JSPlayM4_SetSycGroup"] = Module["asm"]["JSPlayM4_SetSycGroup"])
          .apply(null, arguments)
      };
      var _JSPlayM4_SetSmartFirstKeyFrameDisplay = Module["_JSPlayM4_SetSmartFirstKeyFrameDisplay"] = function() {
        return (_JSPlayM4_SetSmartFirstKeyFrameDisplay = Module["_JSPlayM4_SetSmartFirstKeyFrameDisplay"] =
          Module["asm"]["JSPlayM4_SetSmartFirstKeyFrameDisplay"]).apply(null, arguments)
      };
      var _JSPlayM4_GetRawData = Module["_JSPlayM4_GetRawData"] = function() {
        return (_JSPlayM4_GetRawData = Module["_JSPlayM4_GetRawData"] = Module["asm"]["JSPlayM4_GetRawData"])
          .apply(null, arguments)
      };
      var _JSPlayM4_VideoDataToBMP = Module["_JSPlayM4_VideoDataToBMP"] = function() {
        return (_JSPlayM4_VideoDataToBMP = Module["_JSPlayM4_VideoDataToBMP"] = Module["asm"][
          "JSPlayM4_VideoDataToBMP"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_VideoDataToJpeg = Module["_JSPlayM4_VideoDataToJpeg"] = function() {
        return (_JSPlayM4_VideoDataToJpeg = Module["_JSPlayM4_VideoDataToJpeg"] = Module["asm"][
          "JSPlayM4_VideoDataToJpeg"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetRunTimeInfoCallBackEx = Module["_JSPlayM4_SetRunTimeInfoCallBackEx"] = function() {
        return (_JSPlayM4_SetRunTimeInfoCallBackEx = Module["_JSPlayM4_SetRunTimeInfoCallBackEx"] = Module[
          "asm"]["JSPlayM4_SetRunTimeInfoCallBackEx"]).apply(null, arguments)
      };
      var _JSPlayM4_SetPlayOrBackSwitchMode = Module["_JSPlayM4_SetPlayOrBackSwitchMode"] = function() {
        return (_JSPlayM4_SetPlayOrBackSwitchMode = Module["_JSPlayM4_SetPlayOrBackSwitchMode"] = Module["asm"][
          "JSPlayM4_SetPlayOrBackSwitchMode"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetStretchPlay = Module["_JSPlayM4_SetStretchPlay"] = function() {
        return (_JSPlayM4_SetStretchPlay = Module["_JSPlayM4_SetStretchPlay"] = Module["asm"][
          "JSPlayM4_SetStretchPlay"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetAutoSmoothPlay = Module["_JSPlayM4_SetAutoSmoothPlay"] = function() {
        return (_JSPlayM4_SetAutoSmoothPlay = Module["_JSPlayM4_SetAutoSmoothPlay"] = Module["asm"][
          "JSPlayM4_SetAutoSmoothPlay"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_KeepPlaySpeed = Module["_JSPlayM4_KeepPlaySpeed"] = function() {
        return (_JSPlayM4_KeepPlaySpeed = Module["_JSPlayM4_KeepPlaySpeed"] = Module["asm"][
          "JSPlayM4_KeepPlaySpeed"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_SetPrivateInfoCallBack = Module["_JSPlayM4_SetPrivateInfoCallBack"] = function() {
        return (_JSPlayM4_SetPrivateInfoCallBack = Module["_JSPlayM4_SetPrivateInfoCallBack"] = Module["asm"][
          "JSPlayM4_SetPrivateInfoCallBack"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_FEC_GetPort = Module["_JSPlayM4_FEC_GetPort"] = function() {
        return (_JSPlayM4_FEC_GetPort = Module["_JSPlayM4_FEC_GetPort"] = Module["asm"]["JSPlayM4_FEC_GetPort"])
          .apply(null, arguments)
      };
      var _JSPlayM4_FEC_Enable = Module["_JSPlayM4_FEC_Enable"] = function() {
        return (_JSPlayM4_FEC_Enable = Module["_JSPlayM4_FEC_Enable"] = Module["asm"]["JSPlayM4_FEC_Enable"])
          .apply(null, arguments)
      };
      var _JSPlayM4_FEC_SetParam = Module["_JSPlayM4_FEC_SetParam"] = function() {
        return (_JSPlayM4_FEC_SetParam = Module["_JSPlayM4_FEC_SetParam"] = Module["asm"][
          "JSPlayM4_FEC_SetParam"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_FEC_SetViewParam = Module["_JSPlayM4_FEC_SetViewParam"] = function() {
        return (_JSPlayM4_FEC_SetViewParam = Module["_JSPlayM4_FEC_SetViewParam"] = Module["asm"][
          "JSPlayM4_FEC_SetViewParam"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_FEC_SetWnd = Module["_JSPlayM4_FEC_SetWnd"] = function() {
        return (_JSPlayM4_FEC_SetWnd = Module["_JSPlayM4_FEC_SetWnd"] = Module["asm"]["JSPlayM4_FEC_SetWnd"])
          .apply(null, arguments)
      };
      var _JSPlayM4_FEC_DelPort = Module["_JSPlayM4_FEC_DelPort"] = function() {
        return (_JSPlayM4_FEC_DelPort = Module["_JSPlayM4_FEC_DelPort"] = Module["asm"]["JSPlayM4_FEC_DelPort"])
          .apply(null, arguments)
      };
      var _JSPlayM4_FEC_Disable = Module["_JSPlayM4_FEC_Disable"] = function() {
        return (_JSPlayM4_FEC_Disable = Module["_JSPlayM4_FEC_Disable"] = Module["asm"]["JSPlayM4_FEC_Disable"])
          .apply(null, arguments)
      };
      var _JSPlayM4_FEC_ResetCorrectType = Module["_JSPlayM4_FEC_ResetCorrectType"] = function() {
        return (_JSPlayM4_FEC_ResetCorrectType = Module["_JSPlayM4_FEC_ResetCorrectType"] = Module["asm"][
          "JSPlayM4_FEC_ResetCorrectType"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_FEC_SetDisplayRegion = Module["_JSPlayM4_FEC_SetDisplayRegion"] = function() {
        return (_JSPlayM4_FEC_SetDisplayRegion = Module["_JSPlayM4_FEC_SetDisplayRegion"] = Module["asm"][
          "JSPlayM4_FEC_SetDisplayRegion"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetFishEye2DParam = Module["_JSPlayM4_GetFishEye2DParam"] = function() {
        return (_JSPlayM4_GetFishEye2DParam = Module["_JSPlayM4_GetFishEye2DParam"] = Module["asm"][
          "JSPlayM4_GetFishEye2DParam"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetFishEyeViewParam = Module["_JSPlayM4_GetFishEyeViewParam"] = function() {
        return (_JSPlayM4_GetFishEyeViewParam = Module["_JSPlayM4_GetFishEyeViewParam"] = Module["asm"][
          "JSPlayM4_GetFishEyeViewParam"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_GetViewParam = Module["_JSPlayM4_GetViewParam"] = function() {
        return (_JSPlayM4_GetViewParam = Module["_JSPlayM4_GetViewParam"] = Module["asm"][
          "JSPlayM4_GetViewParam"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_FEC_SetCanvasID = Module["_JSPlayM4_FEC_SetCanvasID"] = function() {
        return (_JSPlayM4_FEC_SetCanvasID = Module["_JSPlayM4_FEC_SetCanvasID"] = Module["asm"][
          "JSPlayM4_FEC_SetCanvasID"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_FEC_SetBackCilling = Module["_JSPlayM4_FEC_SetBackCilling"] = function() {
        return (_JSPlayM4_FEC_SetBackCilling = Module["_JSPlayM4_FEC_SetBackCilling"] = Module["asm"][
          "JSPlayM4_FEC_SetBackCilling"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_FEC_GetPTZPort = Module["_JSPlayM4_FEC_GetPTZPort"] = function() {
        return (_JSPlayM4_FEC_GetPTZPort = Module["_JSPlayM4_FEC_GetPTZPort"] = Module["asm"][
          "JSPlayM4_FEC_GetPTZPort"
        ]).apply(null, arguments)
      };
      var _JSPlayM4_FEC_GetParam = Module["_JSPlayM4_FEC_GetParam"] = function() {
        return (_JSPlayM4_FEC_GetParam = Module["_JSPlayM4_FEC_GetParam"] = Module["asm"][
          "JSPlayM4_FEC_GetParam"
        ]).apply(null, arguments)
      };
      var __emscripten_tls_init = Module["__emscripten_tls_init"] = function() {
        return (__emscripten_tls_init = Module["__emscripten_tls_init"] = Module["asm"]["_emscripten_tls_init"])
          .apply(null, arguments)
      };
      var _pthread_self = Module["_pthread_self"] = function() {
        return (_pthread_self = Module["_pthread_self"] = Module["asm"]["pthread_self"]).apply(null, arguments)
      };
      var ___getTypeName = function() {
        return (___getTypeName = Module["asm"]["__getTypeName"]).apply(null, arguments)
      };
      var __embind_initialize_bindings = Module["__embind_initialize_bindings"] = function() {
        return (__embind_initialize_bindings = Module["__embind_initialize_bindings"] = Module["asm"][
          "_embind_initialize_bindings"
        ]).apply(null, arguments)
      };
      var ___errno_location = function() {
        return (___errno_location = Module["asm"]["__errno_location"]).apply(null, arguments)
      };
      var __emscripten_thread_init = Module["__emscripten_thread_init"] = function() {
        return (__emscripten_thread_init = Module["__emscripten_thread_init"] = Module["asm"][
          "_emscripten_thread_init"
        ]).apply(null, arguments)
      };
      var __emscripten_thread_crashed = Module["__emscripten_thread_crashed"] = function() {
        return (__emscripten_thread_crashed = Module["__emscripten_thread_crashed"] = Module["asm"][
          "_emscripten_thread_crashed"
        ]).apply(null, arguments)
      };
      var _emscripten_main_runtime_thread_id = function() {
        return (_emscripten_main_runtime_thread_id = Module["asm"]["emscripten_main_runtime_thread_id"]).apply(
          null, arguments)
      };
      var _emscripten_main_thread_process_queued_calls = function() {
        return (_emscripten_main_thread_process_queued_calls = Module["asm"][
          "emscripten_main_thread_process_queued_calls"
        ]).apply(null, arguments)
      };
      var __emscripten_run_in_main_runtime_thread_js = function() {
        return (__emscripten_run_in_main_runtime_thread_js = Module["asm"][
          "_emscripten_run_in_main_runtime_thread_js"
        ]).apply(null, arguments)
      };
      var _emscripten_dispatch_to_thread_ = function() {
        return (_emscripten_dispatch_to_thread_ = Module["asm"]["emscripten_dispatch_to_thread_"]).apply(null,
          arguments)
      };
      var __emscripten_thread_free_data = function() {
        return (__emscripten_thread_free_data = Module["asm"]["_emscripten_thread_free_data"]).apply(null,
          arguments)
      };
      var __emscripten_thread_exit = Module["__emscripten_thread_exit"] = function() {
        return (__emscripten_thread_exit = Module["__emscripten_thread_exit"] = Module["asm"][
          "_emscripten_thread_exit"
        ]).apply(null, arguments)
      };
      var _malloc = Module["_malloc"] = function() {
        return (_malloc = Module["_malloc"] = Module["asm"]["malloc"]).apply(null, arguments)
      };
      var __emscripten_check_mailbox = Module["__emscripten_check_mailbox"] = function() {
        return (__emscripten_check_mailbox = Module["__emscripten_check_mailbox"] = Module["asm"][
          "_emscripten_check_mailbox"
        ]).apply(null, arguments)
      };
      var _free = Module["_free"] = function() {
        return (_free = Module["_free"] = Module["asm"]["free"]).apply(null, arguments)
      };
      var _setThrew = function() {
        return (_setThrew = Module["asm"]["setThrew"]).apply(null, arguments)
      };
      var _emscripten_stack_set_limits = function() {
        return (_emscripten_stack_set_limits = Module["asm"]["emscripten_stack_set_limits"]).apply(null,
          arguments)
      };
      var stackSave = function() {
        return (stackSave = Module["asm"]["stackSave"]).apply(null, arguments)
      };
      var stackRestore = function() {
        return (stackRestore = Module["asm"]["stackRestore"]).apply(null, arguments)
      };
      var stackAlloc = function() {
        return (stackAlloc = Module["asm"]["stackAlloc"]).apply(null, arguments)
      };
      var ___cxa_is_pointer_type = function() {
        return (___cxa_is_pointer_type = Module["asm"]["__cxa_is_pointer_type"]).apply(null, arguments)
      };
      var dynCall_jiji = Module["dynCall_jiji"] = function() {
        return (dynCall_jiji = Module["dynCall_jiji"] = Module["asm"]["dynCall_jiji"]).apply(null, arguments)
      };
      var dynCall_iij = Module["dynCall_iij"] = function() {
        return (dynCall_iij = Module["dynCall_iij"] = Module["asm"]["dynCall_iij"]).apply(null, arguments)
      };
      var ___emscripten_embedded_file_data = Module["___emscripten_embedded_file_data"] = 76228;

      function invoke_viiii(index, a1, a2, a3, a4) {
        var sp = stackSave();
        try {
          getWasmTableEntry(index)(a1, a2, a3, a4)
        } catch (e) {
          stackRestore(sp);
          if (e !== e + 0) throw e;
          _setThrew(1, 0)
        }
      }

      function invoke_iii(index, a1, a2) {
        var sp = stackSave();
        try {
          return getWasmTableEntry(index)(a1, a2)
        } catch (e) {
          stackRestore(sp);
          if (e !== e + 0) throw e;
          _setThrew(1, 0)
        }
      }

      function invoke_iiiii(index, a1, a2, a3, a4) {
        var sp = stackSave();
        try {
          return getWasmTableEntry(index)(a1, a2, a3, a4)
        } catch (e) {
          stackRestore(sp);
          if (e !== e + 0) throw e;
          _setThrew(1, 0)
        }
      }

      function invoke_iiii(index, a1, a2, a3) {
        var sp = stackSave();
        try {
          return getWasmTableEntry(index)(a1, a2, a3)
        } catch (e) {
          stackRestore(sp);
          if (e !== e + 0) throw e;
          _setThrew(1, 0)
        }
      }

      function invoke_vi(index, a1) {
        var sp = stackSave();
        try {
          getWasmTableEntry(index)(a1)
        } catch (e) {
          stackRestore(sp);
          if (e !== e + 0) throw e;
          _setThrew(1, 0)
        }
      }

      function intArrayFromBase64(s) {
        try {
          var decoded = atob(s);
          var bytes = new Uint8Array(decoded.length);
          for (var i = 0; i < decoded.length; ++i) {
            bytes[i] = decoded.charCodeAt(i)
          }
          return bytes
        } catch (_) {
          throw new Error("Converting base64 string to bytes failed.")
        }
      }
      Module["addRunDependency"] = addRunDependency;
      Module["removeRunDependency"] = removeRunDependency;
      Module["FS_createPath"] = FS.createPath;
      Module["FS_createDataFile"] = FS.createDataFile;
      Module["FS_createLazyFile"] = FS.createLazyFile;
      Module["FS_createDevice"] = FS.createDevice;
      Module["FS_unlink"] = FS.unlink;
      Module["keepRuntimeAlive"] = keepRuntimeAlive;
      Module["wasmMemory"] = wasmMemory;
      Module["print"] = out;
      Module["ccall"] = ccall;
      Module["addFunction"] = addFunction;
      Module["setValue"] = setValue;
      Module["getValue"] = getValue;
      Module["UTF8ToString"] = UTF8ToString;
      Module["writeArrayToMemory"] = writeArrayToMemory;
      Module["ExitStatus"] = ExitStatus;
      Module["FS_createPreloadedFile"] = FS.createPreloadedFile;
      Module["PThread"] = PThread;
      var calledRun;
      dependenciesFulfilled = function runCaller() {
        if (!calledRun) run();
        if (!calledRun) dependenciesFulfilled = runCaller
      };

      function run() {
        if (runDependencies > 0) {
          return
        }
        if (ENVIRONMENT_IS_PTHREAD) {
          readyPromiseResolve(Module);
          initRuntime();
          startWorker(Module);
          return
        }
        preRun();
        if (runDependencies > 0) {
          return
        }

        function doRun() {
          if (calledRun) return;
          calledRun = true;
          Module["calledRun"] = true;
          if (ABORT) return;
          initRuntime();
          readyPromiseResolve(Module);
          if (Module["onRuntimeInitialized"]) Module["onRuntimeInitialized"]();
          postRun()
        }
        if (Module["setStatus"]) {
          Module["setStatus"]("Running...");
          setTimeout(function() {
            setTimeout(function() {
              Module["setStatus"]("")
            }, 1);
            doRun()
          }, 1)
        } else {
          doRun()
        }
      }
      if (Module["preInit"]) {
        if (typeof Module["preInit"] == "function") Module["preInit"] = [Module["preInit"]];
        while (Module["preInit"].length > 0) {
          Module["preInit"].pop()()
        }
      }
      run();


      return moduleArg.ready
    }

  );
})();
if (typeof exports === 'object' && typeof module === 'object')
  module.exports = JSPlayerModule;
else if (typeof define === 'function' && define['amd'])
  define([], function() {
    return JSPlayerModule;
  });
else if (typeof exports === 'object')
  exports["JSPlayerModule"] = JSPlayerModule;